通用方法中的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
,你不能将MyOtherSpecialNode
为MySpecialNode
。
编辑 :您可以使用这样的单一演员:
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
(你可以安全地做,因为你已经检查过T
是SpecialNode
)。
很容易将其视为编译器的缺点; 但这只是一个错误源于MySpecialNode
看起来很明显。 假设我有一个这样的方法:
public T Get() { if (typeof(T).FullName.Equals("System.Int32")) return 5; else return default(T); }
这会编译吗? 我不希望; 编译器需要保证它返回一个类型为T
的对象,并且不能确定5
只是从开发人员执行的一些奇怪的检查中满足该要求。 (是的, 我知道T
是int
,但我不希望任何合理的编译器通过比较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?