[英]implict type cast in generic method
为什么我在下面的代码中得到一个编译器错误说明:即使T必须从我在where子句中定义的NodeBase派生,即使SpecialNode实际上是从NodeBase派生的, Cannot implicty convert type SpecialNode to T
public static T GetNode<T>() 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
,如下所示:
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<T>() 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
是一个T
。 假设我有这样的方法:
public T Get<T>() {
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))
是否真的没有那么不同。
啊,那一刻你希望语言有某种静态多态性。 通用方法中的类型检查不是很酷。 如果您的要求允许,这可以是更好的解决方案:
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<T>() where T : NodeBase, new()
{
return (T)new T().GetNode();
}
这有一个缺点,你必须暴露无参数的构造函数。 如果这是不合需要的, 可能稍微好一点的方法是将通用调用向后推一层,并要求静态类本身为您完成工作。 将静态类定义更改为:
public static T GetNode<T>() where T : NodeBase
{
return ThisStaticClass<T>.GetNode();
}
//in which case ThisStaticClass<T> have awareness of
//parameterless new() constructor of T class, which still need not be good enough
你可以通过更深入地了解一个通用级别来获得更强的类型。
public abstract class NodeBase<T> where T : NodeBase<T>
{
public abstract T GetNode();
}
public class SpecialNode : NodeBase<SpecialNode>
{
public override SpecialNode GetNode()
{
return ThisStaticClass.MySpecialNode;
}
}
public class OtherSpecialNode : NodeBase<OtherSpecialNode>
{
public override OtherSpecialNode GetNode()
{
return ThisStaticClass.MyOtherSpecialNode;
}
}
//avoids cast
public static T GetNode<T>() where T : NodeBase<T>, new()
{
return new T().GetNode();
}
问题是可以使用类型参数T
调用该函数,该类型参数T
来自NodeBase
但不来自SpecialNode
。 编译器不检查if
语句的语义,因此它不知道T必须是specialNode
。
您需要对T
使用显式强制转换才能满足您的编译器。
你也可以这样做:
public static T GetNode<T>() 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);
}
编辑:如果静态类已经为空,这可能不会产生预期的效果。
为什么不这样做:
return (T)MySpecialNode;
什么版本的.NET?
请参阅上一篇文章中的答案
使用Generics返回文字字符串或从Dictionary <string,object>
但答案是
return (T)MySpecialNode
因为即使你做了if检查编译器没有,所以你必须重新转换为T.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.