为什么我在下面的代码中得到编译器错误:Cannot implicty convert type SpecialNode to T
即使T必须从我在where子句中定义的NodeBase派生,即使SpecialNode实际上是从NodeBase派生的?
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);
}
答案 0 :(得分:4)
编译器没有阅读您的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;
答案 1 :(得分:3)
您可能会发现逻辑上符合条件,但编译器不会“记住”此情况。
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);
}
其他人已经说过这是真的:你必须施展MySpecialNode
:(T)(NodeBase)MySpecialNode
(你可以安全地做,因为你已经检查了T
是SpecialNode
)。
很容易将此视为编译器的缺点;但这只是一个错误,因为{em>似乎 MySpecialNode
是T
是多么明显。假设我有这样的方法:
public T Get<T>() {
if (typeof(T).FullName.Equals("System.Int32"))
return 5;
else
return default(T);
}
这个应该编译吗?我不希望;编译器需要保证它返回一个T
类型的对象,并且不能确定5
只是通过一些奇怪的检查 I 来满足该要求开发人员已经执行了。 (是的,我知道T
是int
,但我不希望任何合理的编译器通过比较System.Type.FullName
属性来确定它。)< / p>
检查if (typeof(T) == typeof(SpecialNode))
实际上并没有那么不同。
答案 2 :(得分:0)
问题是可以使用类型参数T
调用该函数,该参数派生自NodeBase
但不来自SpecialNode
。编译器不检查if
语句的语义,因此它不知道T必须是specialNode
。
您需要对T
使用显式强制转换才能满足您的编译器。
答案 3 :(得分:0)
你也可以这样做:
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);
}
编辑:如果静态类已经为空,则可能无法达到预期的效果。
答案 4 :(得分:0)
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();
}
答案 5 :(得分:-1)
请参阅上一篇文章中的答案
Using Generics to return a literal string or from Dictionary<string, object>
但答案是
return (T)MySpecialNode
因为即使您执行if检查编译器没有这样做,您也必须重新编译为T
答案 6 :(得分:-2)
为什么不执行以下操作:
return (T)MySpecialNode;
什么版本的.NET?