约束泛型参数从子类型转换为超类型

时间:2013-01-27 12:17:49

标签: c# generics type-conversion .net-4.5

我有这样的通用函数:

private LOCAL_TYPE RemoteToLocal<LOCAL_TYPE>(RemoteObjectBaseType remoteObject)
        where LOCAL_TYPE: EntityBase
    {
        Type t = typeof(LOCAL_TYPE);
        if (t == typeof(FavoritePlace))
        {
            return new FavoritePlace(remoteObject as RemotePlaceType1);
        }
    }

其中EntityBase是非抽象类。 FavoritePlace类继承自EntityBase

然而,我收到一个错误:

  

无法将Common.Model.FavoritePlace类型隐式转换为'LOCAL_TYPE'。

这让我想知道:FavoritePlace是EntityBase的子节点,LOCAL_TYPE被约束为EntityBase类型。为什么不能进行转换?我可能在这里遗漏了一些重要的东西。

编辑:好的,根据目前的答案和一些实验,我找到了另一种解决方法,即进行以下转换:

if (t == typeof(FavoritePlace))
    {
        return (LOCAL_TYPE)(EntityBase)new FavoritePlace(remoteObject);
    }

现在编译器很高兴。但我只是想知道,如果从编译器的角度可以进行这样的转换,为什么不直接转换为LOCAL_TYPE? 是否可以转换为关系传递?

2 个答案:

答案 0 :(得分:2)

问题是FavoritePlace不一定是LOCAL_TYPE的类型。 如果你有

class OtherEntity : EntityBase { }

然后在调用

时无法返回FavoritePlace
var entity = RemoteToLocal<OtherEntity>(remoteObject);

如果你知道转换是安全的,你可以通过演员来解决它:

return (LOCAL_TYPE)(object)new FavoritePlace(remoteObject as RemotePlaceType1);

答案 1 :(得分:1)

虽然您已通过运行时代码确定LOCAL_TYPE实际上是FavoritePlace,但编译器没有相同的知识静态 。编译器希望您返回类型为LOCAL_TYPE的对象,该对象与该方法的类型参数完全匹配。

想到这种情况:有人拨打以下电话 -

var res = RemoteToLocal<MostHatedPlace>(remoteObj); // MostHatedPlace derives from EntityBase

现在你在RemoteToLocal内,你经历了一些条件,现在是时候返回结果了。你打电话

return new FavoritePlace(remoteObject as RemotePlaceType1);

你知道代码中的这个分支是不可能达到的,因为有一个运行时检查可以保护你:

if (t == typeof(FavoritePlace)) {
    ....
}

但是,编译器必须假定可以达到此返回语句,如果LOCAL_TYPE a FavoritePlace,则会出错。

您可能需要在此处重新考虑泛型的使用:从代码片段看,您需要使用泛型参数来避免将结果类型转换为调用者中的所需类型。但是,调用者需要执行额外检查以查看RemoteToLocal内的转换是否成功。在这种情况下,方法

private EntityBase RemoteToLocal(RemoteObjectBaseType remoteObject) {
    ....
}

可能同样适合于任务,因为它不会有欺骗编译器的转换,并且调用代码的结构将保持不变。