通用方法中的implict类型转换

为什么我在下面的代码中得到一个编译器错误说明:即使T必须从我在where子句中定义的NodeBase派生,即使SpecialNode实际上是从NodeBase派生的, Cannot implicty convert type SpecialNode to T

  public static T GetNode() where T : NodeBase { if (typeof(T) == typeof(SpecialNode)) { return ThisStaticClass.MySpecialNode; // <-- compiler error } if (typeof(T) == typeof(OtherSpecialNode)) { return ThisStaticClass.MyOtherSpecialNode; // <-- compiler error } ... return default(T); } 

编译器不会读取你的if检查以意识到在这个特定的行中, T必须是SpecialNode

您需要首先NodeBase转换为NodeBase ,如下所示:

 return (T)(NodeBase)MySpecialNode; 

你需要强制转换,因为(据编译器知道) T可能是MyOtherSpecialNode ,你不能将MyOtherSpecialNodeMySpecialNode

编辑 :您可以使用这样的单一演员:

 NodeBase retVal; if (typeof(T) == typeof(SpecialNode)) retVal = MySpecialNode; else if (typeof(T) == typeof(OtherSpecialNode)) retVal = MyOtherSpecialNode; return (T)retVal; 

可能会看到逻辑上满足条件,但编译器不会“记住”这个。

 public static T GetNode() where T : NodeBase { if (typeof(T) == typeof(SpecialNode)) // OK, you now know T is SpecialNode { // the compiler still insists on returning a T, // and will not assume that MySpecialNode is a T return MySpecialNode; } // ... return default(T); } 

其他人已经说过这是真的:你必须(T)(NodeBase)MySpecialNode MySpecialNode(T)(NodeBase)MySpecialNode (你可以安全地做,因为你已经检查过TSpecialNode )。

很容易将其视为编译器的缺点; 但这只是一个错误源于MySpecialNode 看起来很明显。 假设我有一个这样的方法:

 public T Get() { if (typeof(T).FullName.Equals("System.Int32")) return 5; else return default(T); } 

这会编译吗? 我不希望; 编译器需要保证它返回一个类型为T的对象,并且不能确定5只是从开发人员执行的一些奇怪的检查中满足该要求。 (是的, 知道Tint ,但我不希望任何合理的编译器通过比较System.Type.FullName属性来确定它。)

检查if (typeof(T) == typeof(SpecialNode))是否真的没有那么不同。

问题是可以使用类型参数T调用该函数,该类型参数T来自NodeBase但不来自SpecialNode 。 编译器不检查if语句的语义,因此它不知道T必须是specialNode

您需要使用显式强制转换为T以满足您的编译器。

你也可以这样做:

 public static T GetNode() where T : NodeBase { T result; result = ThisStaticClass.MySpecialNode as T; if (result != null) return result; result = ThisStaticClass.MyOtherSpecialNode as T; if (result != null) return result; return default(T); } 

编辑:如果静态类已经为null,则可能没有预期的效果。

啊,那一刻你希望语言有某种静态多态性。 通用方法中的类型检查不是很酷。 如果您的要求允许,这可以是更好的解决方案:

 public abstract class NodeBase { public abstract NodeBase GetNode(); } public class SpecialNode : NodeBase { public override NodeBase GetNode() { return ThisStaticClass.MySpecialNode; } } public class OtherSpecialNode : NodeBase { public override NodeBase GetNode() { return ThisStaticClass.MyOtherSpecialNode; } } //and in your generic method, just: public static T GetNode() where T : NodeBase, new() { return (T)new T().GetNode(); } 

这有一个缺点,你必须暴露无参数的构造函数。 如果这是不合需要的, 可能稍微好一点的方法是将通用调用向后推一层,并要求静态类本身为您完成工作。 将静态类定义更改为:

 public static T GetNode() where T : NodeBase { return ThisStaticClass.GetNode(); } //in which case ThisStaticClass have awareness of //parameterless new() constructor of T class, which still need not be good enough 

你可以通过更深入地了解一个通用级别来获得更强的类型。

 public abstract class NodeBase where T : NodeBase { public abstract T GetNode(); } public class SpecialNode : NodeBase { public override SpecialNode GetNode() { return ThisStaticClass.MySpecialNode; } } public class OtherSpecialNode : NodeBase { public override OtherSpecialNode GetNode() { return ThisStaticClass.MyOtherSpecialNode; } } //avoids cast public static T GetNode() where T : NodeBase, new() { return new T().GetNode(); } 

请参阅上一篇文章中的答案

使用Generics返回文字字符串或从Dictionary

但答案是

 return (T)MySpecialNode 

因为即使你做了if检查编译器没有,所以你必须重新转换为T.

为什么不做以下事情:

 return (T)MySpecialNode; 

什么版本的.NET?