我有一个问题需要解决,涉及到集合的返回与协变问题。我想知道是否有更好的解决方案。
情景如下:
我有两种实现版本,并希望将这两个版本完全分离(尽管它们可能具有相同的逻辑)。在实现中,我想返回一组项目并且在接口中,我会返回项目接口的列表。然而,在接口的实际实现中,我想返回项目的具体对象。代码示例如下。
然后,将会有两个命名空间来实现这些接口。例如:
命名空间 Version1
然而,我希望用户能够像这样做某些事情。
但是,由于它已被转换为另一个列表,因此添加不会做任何事情,因为该项不会被添加回原始结果对象。
我可以想到一些解决方案,例如:
1.我可以同步这两个列表,但这似乎是额外的工作。
2.返回IEnumerable而不是IList,并添加一个用于创建/删除集合的方法。
3.创建一个自定义集合,它采用TConcrete和TInterface。
我理解为什么会发生这种情况(由于类型安全等),但我认为我所想到的解决方法都不太优雅。有人有更好的解决方案或建议吗?
提前感谢!
更新
经过更多思考,我认为我可以这样做:
然后我就可以拥有。
那么,如果调用者正在访问Result类,它将通过CustomCollection.Add(TConcrete item)进行处理,该项已经是TConcrete类型。如果调用者通过IResult接口进行访问,则会通过customCollection.Add(TInterface item)进行处理,并进行验证以确保类型实际上是TConcrete。
情景如下:
我有两种实现版本,并希望将这两个版本完全分离(尽管它们可能具有相同的逻辑)。在实现中,我想返回一组项目并且在接口中,我会返回项目接口的列表。然而,在接口的实际实现中,我想返回项目的具体对象。代码示例如下。
interface IItem
{
// some properties here
}
interface IResult
{
IList<IItem> Items { get; }
}
然后,将会有两个命名空间来实现这些接口。例如:
命名空间 Version1
class Item : IItem
class Result : IResult
{
public List<Item> Items
{
get { // get the list from somewhere }
}
IList<IItem> IResult.Items
{
get
{
// due to covariance, i have to convert it
return this.Items.ToList<IItem>();
}
}
}
在命名空间Version2下,将会有相同事物的另一种实现。
为了创建这些对象,将会有一个工厂来接收版本信息,并根据需要创建相应的具体类型。
如果调用者知道确切的版本并执行以下操作,则代码可以正常工作。
Version1.Result result = new Version1.Result();
result.Items.Add(//something);
然而,我希望用户能够像这样做某些事情。
IResult result = // create from factory
result.Items.Add(//something);
但是,由于它已被转换为另一个列表,因此添加不会做任何事情,因为该项不会被添加回原始结果对象。
我可以想到一些解决方案,例如:
1.我可以同步这两个列表,但这似乎是额外的工作。
2.返回IEnumerable而不是IList,并添加一个用于创建/删除集合的方法。
3.创建一个自定义集合,它采用TConcrete和TInterface。
我理解为什么会发生这种情况(由于类型安全等),但我认为我所想到的解决方法都不太优雅。有人有更好的解决方案或建议吗?
提前感谢!
更新
经过更多思考,我认为我可以这样做:
public interface ICustomCollection<TInterface> : ICollection<TInterface>
{
}
public class CustomCollection<TConcrete, TInterface> : ICustomCollection<TInterface> where TConcrete : class, TInterface
{
public void Add(TConcrete item)
{
// do add
}
void ICustomCollection<TInterface>.Add(TInterface item)
{
// validate that item is TConcrete and add to the collection.
// otherwise throw exception indicating that the add is not allowed due to incompatible type
}
// rest of the implementation
}
然后我就可以拥有。
interface IResult
{
ICustomCollection<IItem> Items { get; }
}
then for implementation, I will have
class Result : IResult
{
public CustomCollection<Item, IItem> Items { get; }
ICustomCollection<TItem> IResult.Items
{
get { return this.Items; }
}
}
那么,如果调用者正在访问Result类,它将通过CustomCollection.Add(TConcrete item)进行处理,该项已经是TConcrete类型。如果调用者通过IResult接口进行访问,则会通过customCollection.Add(TInterface item)进行处理,并进行验证以确保类型实际上是TConcrete。
我会尝试并查看是否有效。
ICollection<T>
而是使用ICustomCollection<T>
呢? - svick