从泛型转换为特定子类

2023-11-23

我有一堂这样的课

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

where, 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类型。唯一的问题是上面的代码无法编译,我不知道为什么

错误是

无法将 T 的表达式转换为 TwoType


正如 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 
} 

现在一切都清楚了吗?您可能会考虑采用完全不同的方法;当你需要这么多的转换和运行时类型检查来说服编译器代码是正确的时,这证明整个事情是一个糟糕的代码味道。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从泛型转换为特定子类 的相关文章

随机推荐