Skip to main content
 首页 » 编程设计

c#之如何在同一个集合中存储不同类型的泛型类(都具有泛型基类)

2024年01月25日22wayfarer

我遇到了与 this post 中类似的问题.

我还看到网上有成千上万的帖子说你可以把任何扩展特定基类的泛型类放入基类类型的集合中。我完全理解这一点。

我的问题在一个基本方面与上面的链接帖子和其他帖子不同——我的泛型类有一个基类,它也是泛型的。更糟糕的是,这是一个非常大的 MVVM 应用程序框架(内部构建)的一部分,通用基类也有一个基类等等......每个基类都添加了某些属性和功能,它看起来有点像这样:

DataListEntry<T> <-- BaseSynchronisableDataType<T> <-- BaseAuditDataType <-- BaseDataType <-- BaseAnimatableDataType

应用程序集合类使用类似的继承:

DataList<T> <-- BaseSynchronisableCollection<T> <-- BaseAnimatableCollection<T> <-- BaseCollection<T> <-- SortableObservableCollection<T>

更糟糕的是,每个泛型声明都有约束,例如,BaseSynchronisableDataType 的定义如下所示:

public abstract class BaseSynchronisableDataType<T> : BaseAuditDataType,  
    ISynchronisable<T>, ICloneable<T>, IEquatable<T> where T : class, ICloneable<T>, 
    IEquatable<T>, new() 

因此每个泛型集合类型都通过这些约束绑定(bind)到一个泛型基类。希望到现在为止,您可以看到我的问题的严重性。

我曾尝试使用接口(interface)(上面未显示)删除集合到它们各自基类的链接,但这也失败了,因为相关类的一些通用约束。例如,我无法创建接口(interface)类型的集合,因为在某些基类上存在必要的通用“类”约束,因此我收到错误消息,指出集合的类型“必须是非抽象类型”公共(public)无参数构造函数,以便将其用作泛型类型或方法中的参数“T”。

要注意的最后一点准确描述了我正在尝试做的事情:

我需要用不同的类填充一个集合,这些类都扩展了 DataList 基类。这些类仅在名称上有所不同,并且具有完全相同的属性。它们声明如下:

public class Writer : DataListEntry<Writer>     
public class Artist : DataListEntry<Artist>etc. 

如果您有任何想法,请告诉我...我已经为这个问题苦恼了 2 天,我的老板一点也不高兴!谢里丹,提前致谢。

请您参考如下方法:

这里有一个您需要了解的关键原则——类 Foo<Child>不是 Foo<Parent> 的子类即使 Child是 Parent 的子类。这意味着 List<Foo<Parent>>不能包含 List<Foo<Child>> 的实例它不能包含字符串或 Int32。

要理解为什么会这样,想象一下下面的代码(它不能编译,但说明了为什么上面的陈述需要为真):

var myIntList = new List<Int>(); 
var myObjectList = (List<Object>)myIntList; 
 
// Uh oh, now I can add a string to a list of integers... 
myObjectList.Add("Foo"); 

您对 curiously recurring template pattern 的使用消除了所有类之间的继承层次结构。因为它们不再共享基类,所以不能将它们放入比 List<Object> 更具体的列表中

在您的情况下,最好的方法可能是制作一个 DataListEntry 实现的非通用接口(interface),并制作该接口(interface)的列表。如果接口(interface)在该类型的实例中提供了您需要的所有成员,那么一切就绪。

例如:

public interface IDataListEntry {  
    bool QuacksLikeADuck { get; }  
    bool WalksLikeADuck { get; } 
} 
 
public abstract class DataListEntry<T> : IDataListEntry where ... { 
    // Implement these in subclasses 
    abstract bool QuacksLikeADuck { get; }  
    abstract bool WalksLikeADuck { get; }  
} 

然后你可以:

List<IDataListEntry> myDataListEntries = new List<IDataListEntry>(); 
myDataListEntries.Add(new Writer(...)); 
myDataListEntries.Add(new Artist(...)); 
IEnumerable ducks = myDataListEntries.Where(dle => dle.WalksLikeADuck && dle.QuacksLikeADuck); 

或者(可能更适合您的情况),如果您需要知道 T 的类型在 IDataListEntry 的特定实例中:

public interface IDataListEntry {  
    Type TheTypeOfT { get; } 
} 
 
public class DataListEntry<T> : IDataListEntry where ... { 
    Type TheTypeOfT { get { return typeof(T); } } 
} 

然后做:

List<IDataListEntry> myDataListEntries = new List<IDataListEntry>(); 
myDataListEntries.Add(new Writer(...)); 
myDataListEntries.Add(new Artist(...)); 
IEnumerable artists = myDataListEntries.Where(dle => typeof(Artist).IsAssignableFrom(dle.TheTypeOfT));