公开列表<;域对象>;经由IList<;界面>;

本文关键字:gt lt 经由 IList 界面 列表 对象 | 更新日期: 2023-09-27 18:29:46

我有一个类型为List<T>的私有成员,其中T是富域对象。我的应用程序中的域包含许多需要T的方法。

我只想公开类型为IList<IT>的公共属性,其中T : IT。CCD_ 6具有由DTO实现的小占地面积。

由于我无法将List<T>强制转换为IList<IT>,所以我在属性声明中使用List<T>.ConvertAll

有更好的方法吗?更快、更优雅?

编辑以提供更多详细信息

T是一个基类,存在许多派生类,这些派生类中的每一个都有许多不同的风格(在运行时加载的配置)。表示层中的用户可以添加/更改/删除任何配置的这些派生类的任何实例。用户也可以将实例定向链接到彼此,但有一些复杂的规则来管理允许的链接;有些在编译时已知,有些仅在运行时已知(基于配置)。有些实例可能是双重链接的,有些是交联的,有些在任一方向上都是单一的,有些只在一个方向上,有些根本不是。

为此,T包含任何此类链路的有效目标的列表。表示层以图形方式高亮显示这些有效目标,如果目标不在有效列表中,则不允许链接。当任何实例被新建、更改或删除时,每个实例的ValidTargets列表都需要重新评估,并且可能会发生更改。

T类上还有许多其他成员和方法,工厂和服务类希望对它们进行操作。有些成员和方法的行为与上面的示例非常相似。这些都不应暴露在组件外部。

公开列表<;域对象>;经由IList<;界面>;

假设您可以执行以下操作:

// NOT REAL CODE
public interface IMyInterface { } 
public class MyRealClass : IMyInterface { } 
...
public class Domain
{
    private List<MyRealClass> myList;
    public IList<IMyInterface> Interfaces { get { return (IList<IMyInterface>)this.myList; } }
}

如何阻止Domain类的用户执行此操作?

public class MyFakeClass : IMyInterface { } 
...
domain.Interfaces.Add(new MyFakeClass());

显然,这是有问题的,因为myList实际上是List<MyRealClass>,但编译器不能确保只有MyRealClass的实例被添加到列表中(这需要运行时检查)。换句话说,这种行为不是类型安全的,所以编译器不允许这样做

您可以公开IMyInterfaceIList/ICollection—这是类型安全的,但不能确保只将您的MyRealClass添加到列表中。

public class Domain
{
    private List<IMyInterface> myList;
    public IList<IMyInterface> Interfaces { get { return this.myList; } }
}

或者,您可以公开IMyInterfaceIEnumerable(或IReadOnlyList,如zmbq所建议的)—因为类型参数是协变的(参见泛型中的协变和逆变)。尽管这不允许您向集合中添加新项目。

public class Domain
{
    private List<MyRealClass> myList;
    public IEnumerable<IMyInterface> Interfaces { get { return this.myList; } }
}

另一个解决方案是实现您自己的集合类,该类实际上实现了IList<IMyInterface>,但如果用户试图插入除MyRealClass之外的任何内容,则会引发异常。这不是一个特别优雅的解决方案,而且在实践中,它与简单地公开IList<MyRealClass>没有什么不同。

如果我理解正确,您应该能够使用Linqs-select方法将列表转换为IList。所以你在做这样的事情:

List<T> myList = ...
IList<IT> b = myList.Select(a=> a as IT).ToList();