繁体   English   中英

通用方法中的implict类型转换

[英]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 ,你不能将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<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 (你可以安全地做,因为你已经检查过TSpecialNode )。

很容易将其视为编译器的缺点; 但是这仅仅是从它看起来多么明显,而产生一个错误MySpecialNode是一个T 假设我有这样的方法:

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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM