正如 Grzenio 正确指出的那样,类型 T 的表达式不能转换为 TwoType。编译器不知道表达式是否保证为 TwoType 类型——这是由“if”语句保证的,但编译器在分析类型时不会考虑 if 语句的含义。相反,编译器假定 T 可以是满足约束的任何类型,包括 ThreeType(从 OneType 但不是 TwoType 派生的类型)。显然,没有从 ThreeType 到 TwoType 的转换,因此也没有从 T 到 TwoType 的转换。
您可以通过说“好吧,将 T 视为对象,然后将该对象转换为 TwoType”来欺骗编译器允许它。一路上的每一步都是合法的——T可以转换为对象,并且可能存在从对象到TwoType的转换,因此编译器允许它。
然后你会遇到从子类转换为同样的问题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>
,但是没有从子类到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
}
现在一切都清楚了吗?您可能会考虑采用完全不同的方法;当你需要这么多的转换和运行时类型检查来说服编译器代码是正确的时,这证明整个事情是一个糟糕的代码味道。