我有一个班级
public class MyClass<T> where T : OneType { T MyObj { get; set; } public MyCLass(T obj) { } } public class SubClass: MyClass<TwoType> { } // snip for other similar class definition
其中,TwoType派生自OneType.
现在,我有这个实用方法
public static MyClass<T> Factory<T>(T vd) where T : OneType { switch(vd.TypeName) { case Constant.TwoType return new SubClass((TwoType)vd); // snip for other type check } }
显然,哪个函数检查vd的类型,并创建适当的MyClass类型.唯一的问题是上面的代码不会编译,我不知道为什么
错误是
Cannot cast expression of T to TwoType
解决方法
正如Grzenio正确指出的那样,T类型的表达式不能转换为TwoType.编译器不知道表达式是保证类型为TwoType – 由“if”语句保证,但编译器在分析类型时不考虑if语句的含义.相反,编译器假定T可以是满足约束的任何类型,包括ThreeType,一种从OneType派生但不是TwoType的类型.显然没有从ThreeType到TwoType的转换,因此也没有从T到TwoType的转换.
您可以通过说“好吧,将T视为对象,然后将对象转换为TwoType”来欺骗编译器允许它.沿途的每一步都是合法的 – T可以转换为对象,并且可能存在从对象到TwoType的转换,因此编译器允许它.
然后,您将遇到从SubClass转换为MyClass< T>的相同问题.同样,您可以先通过强制转换为对象来解决问题.
public static MyClass<T> Factory<T>(T vd) where T:OneType { switch(vd.TypeName) { case Constant.TwoType // WRONG return (MyClass<T>)(object)(new SubClass((TwoType)(object)vd)); // snip for other type check } }
为什么这是错的?好吧,考虑一下这里可能出错的一切.例如:你说
class AnotherTwoType : TwoType { } ... x = Factory<TwoType>(new AnotherTwoType());
怎么了?我们不调用SubClass构造函数,因为参数不完全是TwoType类型,它是从TwoType派生的类型.你可能想要而不是开关
public static MyClass<T> Factory<T>(T vd) where T:OneType { if (vd is TwoType) // STILL WRONG return (MyClass<T>)(object)(new SubClass((TwoType)(object)vd)); // snip for other type check }
这仍然是错误的.再次,想想可能出现的问题:
x = Factory<OneType>(new TwoType());
现在发生了什么?参数是TwoType,我们创建一个新的SubClass,然后尝试将其转换为MyClass< OneType>,但没有从SubClass转换为MyClass< OneType>所以这会崩溃并在运行时死亡.
您工厂的正确代码是
public static MyClass<T> Factory<T>(T vd) where T:OneType { if (vd is TwoType && typeof(T) == typeof(TwoType)) return (MyClass<T>)(object)(new SubClass((TwoType)(object)vd)); // snip for other type check }
现在这一切都清楚了吗?你可以完全考虑一种不同的方法;当你需要这么多的强制转换和运行时类型检查来说服编译器代码是正确的时,证明整个事情都是一个糟糕的代码味道.