表达这个问题很难,我希望下面的代码片段能让事情变得清晰:
public class DemoClass<TBase> where TBase : class
{
public void DemoMethod<T>(T target) where T : TBase
{
//The following line causes a design-time error: Type argument 'T' does not satisfy the 'Class' constraint for type parameter 'T'.
WeakReference<T> demoRef = new WeakReference<T>(target);
}
}WeakReference需要满足class约束的类型T。到目前为止一切都还好但是..。
为什么编译器不能检测到T确实检测到了,因为(实际上) T : TBase : class
发布于 2017-07-05 07:13:49
类为什么编译器不能检测到T确实检测到了,因为(实际上)T: TBase:
?
因为这根本不是真的。除了Poke在他的answer中指出的,这也是非法的,因为所有的值类型都继承自object
var dc = new DemoClass<object>();
dc.DemoMethod(1); //woops, just attempted to create a WeakReference<int>当涉及值类型时,您的推理就会分崩离析。人为的?是的,但是完全合法,所以编译器没有选择,必须认为你的代码是非法的。
更新
Jon Hana在下面的评论中说,在上面的代码中,T不是真正的int,它的object和1被隐式地包装起来,这绝对不是真的。考虑DemoMethod的以下变体
public T DemoMethod<T>(T target) where T : TBase
{
return target;
}和以下代码:
var dc = new DemoClass<object>();
var i = dc.DemoMethod(1);i是int,它不是object。此外,以下代码将正确执行:
long i = dc.DemoMethod(1);这也证明了T不能是已装箱的int,因为隐式转换将在运行时失败;您不能将值类型拆箱为除类型本身以外的任何类型。
当然,您总是可以显式设置T,这也可以很好地编译:
dc.DemoMethod<int>(1);发布于 2017-07-05 06:50:15
让我们来看看the documentation关于T : class的实际含义:
where T : class
类型参数必须是引用类型;这也适用于任何类、接口、委托或数组类型。
不幸的是,如果T是一个接口,这就已经满足了。因此,您可以构造一个简单的示例,从中可以看到传递地应用T : class将不起作用:
public interface ITest { }
public struct Test : ITest { }如果您现在创建一个类,那么您就满足了类型约束,因为ITest在这里是一个“类”。但是,当您调用DemoMethod<Test>方法时,虽然Test继承了ITest,但是您没有T的引用类型。
通常,这些特殊的泛型类型约束不遵循继承规则。这就是为什么它们是单独定义的,并且还没有由类型系统建立。它们是作为一种特殊的语法存在的,因为类型系统不能以其他方式表达约束。
https://stackoverflow.com/questions/44914808
复制相似问题