我在我的图书馆中使用了三个类:
public abstract class Base<TFirst, TSecond>
{
public Base()
{
// actions with ID and Data of TFirst and TSecond
}
}
public abstract class First<TFirstID, TFirstData>
{
public TFirstID ID {get; set;}
public TFirstData Data {get; set;}
}
public abstract class Second<TSecondID, TSecondData>
{
public TSecondID ID {get; set;}
public TSecondData Data {get; set;}
}
如何指定TFirst必须从First继承而TSecond必须从Second继承,而不是在Base中使用ID和数据的泛型类型?
像这样:
public abstract class Base<TFirst, TSecond>
where TFirst : First // without generic-types
...
修改 在类First,Second中,我使用TFirstID和TSecondID作为属性。在Base类我使用这个属性。
答案 0 :(得分:6)
除了引入没有geherics的并行类层次结构并进行一些运行时检查之外,你无法做到这一点:
public abstract class Base<TFirst, TSecond>
where TFirst : First
{
static Base()
{
if(!typeof(TFirst).IsGenericType ||
typeof(TFirst).GetGenericTypeDefinition() != typeof(First<,>))
throw new ArgumentException("TFirst");
}
}
public abstract class First { }
public abstract class First<TFirstID, TFirstData> : First
{
}
或者,您可以使用标记界面(First
)替换IFirst
。
由于为每个closed generic type调用了静态构造函数,因此可以进行运行时检查。
答案 1 :(得分:2)
通常在这样的情况下,我将为First<TFirstID, TFirstData>
构建另一个基类(非泛型)来派生,所以:
public abstract class First{}
public abstract class First<TFirstID, TFirstData>
: First
{
}
然后你可以在你的声明中添加where TFirst : First
。它并不完美,但是如果你小心的话它会起作用。但它可能很棘手,取决于你想要完成的事情 - 你失去了限制类型的所有通用性。
答案 2 :(得分:2)
一种解决方案是让First和Second自己实现一个不依赖于泛型类型参数的接口:
public interface IFirst
{
}
public abstract class First<TFirstID, TFirstData> : IFirst
{
}
然后确保base中的type参数必须使用IFirst
public abstract class Base<TFirst, TSecond>
where TFirst : IFirst
答案 3 :(得分:1)
如果他们依赖于这些项目的签名,这可能会很棘手。我可能会说没有类型签名就创建一个接口或抽象基础。接口更有可能。
答案 4 :(得分:0)
如果可能的话,这就是你要这样做的方式;指定泛型类型约束,允许编译器捕获Base的泛型参数的无效用法。
如果出于某种原因,您根本无法使用泛型类型约束,则强制执行类型检查的唯一方法是向您的逻辑添加运行时检查,如果创建了泛型,则会引发异常指定无效的泛型类型:
public abstract class Base<TFirst, TSecond>
{
public Base()
{
if(!typeof(TFirst).IsAssignableFrom(typeof(First))
throw new InvalidOperationException("TFirst must derive from First.");
if(!typeof(TSecond).IsAssignableFrom(typeof(Second))
throw new InvalidOperationException("TSecond must derive from Second.");
}
}
上面的代码是严重的代码味道。泛型的全部意义是允许类使用许多不同的内部类,同时允许编译器确保使用的参数类型使得泛型类可以使用它们。此外,您仍然必须能够引用First和Second的名称空间(我假设这是您不能首先将它们用作泛型类型参数的原因)。