2012-01-17 102 views
8

考虑下面的类:类和方法层面的泛型类型约束作用

public class DerivedClassPool<TBase> where TBase : class 
{ 
    public TBase Get(Type componentType) 
    { 
     // Not important, but you get the idea 
     return Activator.CreateInstance(componentType) as TBase; 
    } 

    public TDerived SomeMethod<TDerived>() where TDerived : TBase 
    { 
     return Get(typeof(TBase)) as TDerived; 
    } 
} 

注意我已经限制了TBase泛型类的说法应是一个类:where TBase : class
我也制约了TDerived通用方法的参数是TBase或从中衍生出来的东西:where TDerived : TBase

我上as TDerived行错误:

类型参数“TDerived”不能使用的“为”经营者,因为它没有一个类类型约束,也不是一个“类”约束

我明白,为了防止我需要添加约束class的错误,所以我会得到:

where TDerived : class, TBase 

为什么我必须这样做,当TBase已被限制为一个类和TDerived被约束为TBase或从它派生?

+1

请参阅http://stackoverflow.com/questions/8002148/c-sharp-generics-contraints-propagation。埃里克把它放在那里。 – 2012-01-17 16:56:19

+1

@Jason,我认为用'but'读得更好。 – Joey 2012-01-17 16:57:20

+1

@Joey:够公平的。我只是讨厌以'but'开头的句子,尽管现在使用连词开始的句子被认为是正确的。我责怪我的高中英语老师。他是经典英语惯例的守护者。 – 2012-01-17 17:40:52

回答

8

更新:这个问题是the subject of my blog on September 19th, 2011。感谢您的好问题!


为什么我必须这样做,当TBASE已经被限制为一类,并TDerived被限制为一TBASE或从它衍生出来?

因为值类型可以从引用类型派生。 int源自参考类型objectSystem.ValueType,并实现多个接口。这不会使int成为参考类型。

DerivedClassPool<object>的实例调用SomeMethod<int>是完全合法的,因为int是从object派生的。

现在,那里你的批评将被批准的情况下。我们可以构造两种类型参数相互关联的情况,即它们在逻辑上只能是引用类型,但只有其中的一种被语言分类为“已知是引用类型”。

作为读者的练习:你能找到一个吗?对于“已知是参考类型”的精确定义,可能需要仔细阅读规范的第10.1.5节。

+0

是否有可能创建从引用类型(在C#中)派生的我们自己的值类型? – 2012-01-17 16:58:49

+0

@GeorgeDuckett为什么这是相关的? – 2012-01-17 16:59:30

+0

@OskarKjellin:不是,我只是好奇。 :) – 2012-01-17 16:59:50

2

因为TBase可能是一个接口,因此TDerived可能是一个值类型。

+0

TBase需要成为一个班级? – 2012-01-17 16:59:04

+1

你确定吗? http://msdn.microsoft.com/en-us/library/d5x73970.aspx:'类型参数必须是引用类型;这也适用于任何类,接口,委托或数组类型。' – 2012-01-17 16:59:39

+1

不知道。在这种情况下,棘手的'class'的意思是“价值类型” – 2012-01-17 17:01:34