2011-03-25 197 views
5

我在图书馆三类用途:C#泛型类型

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;} 
} 

我怎么可以指定T第一必须从第一个继承和TSecond必须从第二继承,不使用泛型类型为基础ID和数据?

像这样:

public abstract class Base<TFirst, TSecond> 
    where TFirst : First // without generic-types 
... 

编辑: 在班级第一,第二我用TFirstID和TSecondID的性质。在课堂上我使用这个属性。

+0

请问您能澄清一下这个问题吗?一垒? – foson 2011-03-25 15:49:52

+0

你的意思是你**不要**想在哪里TFirst:第一个'我认为你不能这样做,我认为haskell允许这样的事情,不确定。 – gideon 2011-03-25 15:52:11

+0

玻色子:不,先不继承基地 – 2011-03-25 15:53:52

回答

1

如果他们依赖于这些项目的签名,这可能会很棘手。我可能会说创建一个没有类型签名的接口或抽象基础。接口更有可能。

2

通常在这样的情况下,我会建一个基类(非通用)的First<TFirstID, TFirstData>从,所以得出:

public abstract class First{} 

public abstract class First<TFirstID, TFirstData> 
    : First 
{ 
} 

然后你就可以把一个where TFirst : First到你的宣言。这并不完美,但如果你小心的话,它会有效。但是这可能很棘手,取决于你想要完成的事情 - 你失去了限制类型的所有通用性。

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 
{ 
} 

或者,你可以用一个标记接口(IFirst)取代First

运行时检查是可能的,因为每个closed generic type都会调用静态构造函数。

+0

+1非常有趣!但是,他实际上不能将通用的'TFirst'限制为**成为** First ',它仍然可以是从“abstract First”继承的任何东西。我认为这可能是一个反模式没有? – gideon 2011-03-25 15:53:15

2

一个解决办法是有第一和第二实施本身不依赖于泛型类型参数的接口:

public interface IFirst 
{ 
} 

public abstract class First<TFirstID, TFirstData> : IFirst 
{ 
} 

然后确保在碱的类型参数必须使用IFirst

public abstract class Base<TFirst, TSecond> 
    where TFirst : IFirst 
+0

这是避免使用实际类的唯一方法,同时允许使用泛型类型作为Object以外的其他类型。 – KeithS 2011-03-25 15:55:03

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的命名空间(我认为这是您不能将它们用作泛型类型参数的原因)。

+0

我认为你的代码应该是这样的:'typeof(TFirst).IsAssignableFrom(typeof(First <,>))' – 2011-03-25 15:56:06

+0

也许,但我的观点是整件事情是代码味道;应该以几乎任何成本实施泛型类型限制以避免这样的事情。 – KeithS 2011-03-25 15:57:43

+0

当然,我同意你的意见。但是,如果您发布代码,请确保它已编译。否则,不要将它发布在第一位。 – 2011-03-25 15:59:38