2016-07-31 90 views
0

我有一个问题,包装我的头为什么没有编译以下代码片段。为什么我不能将`this`强制转换为泛型?

的Visual Studio标志的第一个具有:

无法将类型 'SOMETYPE' 到 'T'

演员是多余的。

using System; 

public class SomeClass { 
    public T Coerce<T>() { 
     if (typeof(T) == typeof(SomeClass)) 
      return (T)this; // <- Error CS0030 
     else throw new InvalidCastException(); 
    } 
} 

拆除 “多余” 剧组,但只是改变了错误:

无法隐式转换类型 'SomeOtherClass' 到 'T'

using System; 

public class SomeOtherClass { 
    public T Coerce<T>() { 
     if (typeof(T) == typeof(SomeOtherClass)) 
      return this; // <- Error CS0029 
     else throw new InvalidCastException(); 
    } 
} 
+0

如果你解释了你在这里实现的目标,这可能会有所帮助。 –

+2

'return(T)(object)this;' – PetSerAl

+1

你为什么要这样做? –

回答

2

编译器告诉你到底发生了什么错误:你不能隐含地将SomeClass转换为T,但是确实存在两件事你需要注意。

首先,您不能隐式转换为泛型类型,因为在编译时该类型是未知的。您必须明确地投射它,或者 - 如果您确实需要隐式转换 - 请使用继承。

第二件事是需要更多的类型信息(通过约束)来区分值类型和引用类型。现在编译器知道什么都没有T。它可能是一个int,其中一个class永远不能被转换。

为引用类型强制转换为T您需要的class约束,它会工作得很好:

public class SomeClass 
{ 
    public T Coerce<T>() where T : class 
    { 
     if (typeof(T) == typeof(SomeClass)) 
      return this as T; 
     else throw new InvalidCastException(); 
    } 
} 

现在,编译器也将阻止你做这样的事情someClassInstance.Coerce<int>()那就是点。

编辑

至于(T)(object)this的例子,这个作品,因为你就不再铸造thisT。相反,你投thisobject(这将始终工作,因为它是所有其他类型派生自),然后你从object投到T,其作品出于同样的原因。您正在规避编译时检查。

你可以这样做,然后打电话给someClassInstance.Coerce<int>(),它会给你例外“指定的转换无效”。在运行时间。但是,使用通用约束会在编译时间处给出警告。

如果这并不妨碍你,return (dynamic)this;是一个更简单的解决方案。但这种做法有悖于使用泛型的目的。

+0

但是为什么'return(T)(object)this;'没有约束的工作? –

+1

这只是一种欺骗编译器的方式,与使用'dynamic'非常密切相关(如果不转换为正确的类型,将导致令人讨厌的运行时错误)。一个对象可以是任何东西:值类型或引用类型(因为这个原因你不能使用'object'作为通用约束条件) –

+0

更新我的答案,更详细地解释这些不同方法的含义 –

相关问题