C#泛型类型

时间:2011-03-25 15:44:55

标签: c# generics

我在我的图书馆中使用了三个类:

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类我使用这个属性。

5 个答案:

答案 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的名称空间(我假设这是您不能首先将它们用作泛型类型参数的原因)。