2

我有一个与这篇文章中的问题类似的问题。

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

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

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

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

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

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

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

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

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

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

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

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

如果您有任何想法,请告诉我……我已经为这个问题苦恼了 2 天,我的老板很不高兴!非常感谢,谢里登。

4

3 回答 3

7

这里有一个关键原则,你需要理解Foo<Child>——Foo<Parent> 即使ChildParent. 这意味着 aList<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");

您对奇怪重复出现的模板模式的使用消除了所有类之间的继承层次结构。因为它们不再共享一个基类,所以它们不能被放入一个更具体的列表中List<Object>

在您的情况下,最好的方法可能是创建一个 DataListEntry 实现的非通用接口,并列出该接口。如果接口在该类型的实例中提供了您需要的所有成员,那么您就完成了。

例如:

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));
于 2012-08-08T16:52:05.110 回答
0

我会一直回到基础,并使用一些简单的 linq 来获取类过滤列表。

声明您的类型对象列表,DataList<object> L然后当您被要求输入类型时,调用L.OfType<Type>()过滤列表的方法。毕竟 object 将是你可以使用的最通用的东西。您也许可以使用 all 扩展的基本类型,但是因为它是抽象的,我不知道您是否可以在该类型上声明一个列表。

在我自己的代码中,我使用通用约束来实现类似的东西。

public abstract class BusinessObjectBase : //some interfaces
{
    //class stuff and events
}

我有一堆扩展我的基类的对象,现在我可以做到这一点

Collection<BusinessObjectBase> temp = new Collection<BusinessObjectBase>();
temp.Add(new RXEvents());
temp.Add(new RXBattery());
temp.Add(new RXBHA());

我添加到列表中的每个类都是通过扩展 BusinessObjectBase 创建的。您正在尝试一些非常相似的东西,但您的基本实现不同。通过将基类型本身声明为模板化,您正在破坏基类型。Base 与 Base 相同,两者除了对象之外没有任何共同点。

Base<>Base<X>or无关Base<Y>。现在如果你像这样描述它

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

然后您可以将其MyCustomBaseClass用作列表类型,因为您可以保证所有<T>表示的对象都是它的子对象。这似乎违背了创建 BaseSynchronisableDataType 的目的......

于 2012-08-08T16:55:26.097 回答
0

好的,所以问题是我无法声明以下内容

DataList<Artist> artists = new DataList<Artist>();

由于对扩展BaseDataListEntry的泛型BaseSynchronisableCollection<T>类的泛型约束,该类不是泛型的。DataList<T>它必须是类无法扩展T的类型BaseSynchronisableDataType<T>,因为它不是通用的。BaseDataListEntry我需要BaseDataListEntry该类不是通用的,以便我可以将所有不同DataList<T>的集合放入DataList<BaseDataListEntry>视图模型中的集合中(一次一个取决于用户的选择)。

解决方案是创建一个IBaseSynchronisableDataType<T>接口并在通用约束而不是具体BaseSynchronisableDataType<T>类中使用它。然后,我在BaseDataListEntry课堂上实现了它,所以现在所有的约束都得到了满足。不知道为什么我没有早点看到它。

谢谢你所有的时间。

于 2012-08-08T20:56:03.117 回答