泛型方法中的隐式类型转换

时间:2010-05-04 14:00:19

标签: c# generics

为什么我在下面的代码中得到编译器错误: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);
    }

7 个答案:

答案 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(你可以安全地做,因为你已经检查了TSpecialNode)。

很容易将此视为编译器的缺点;但这只是一个错误,因为{em>似乎 MySpecialNodeT是多么明显。假设我有这样的方法:

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

这个应该编译吗?我不希望;编译器需要保证它返回一个T类型的对象,并且不能确定5只是通过一些奇怪的检查 I 来满足该要求开发人员已经执行了。 (是的,知道Tint,但我不希望任何合理的编译器通过比较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?