C# 受约束泛型参数从子类型到超类型的转换

C# 受约束泛型参数从子类型到超类型的转换,c#,generics,type-conversion,.net-4.5,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

我有这样一个通用函数:

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);
        }
    }

现在我很高兴。但我只是想知道,如果从编译器的角度来看,这种转换是可能的,为什么直接转换为本地类型是不可能的呢?不是可以转换为关系传递吗?

问题是
收藏地点
不一定是
本地类型的类型。
如果你有

class OtherEntity : EntityBase { }
那么您在呼叫时无法返回
FavoritePlace

var entity = RemoteToLocal<OtherEntity>(remoteObject);

虽然您通过运行时代码确定
LOCAL\u TYPE
实际上是
FavoritePlace
,但编译器静态上并不具备相同的知识。编译器希望您返回类型为
LOCAL\u type
的对象,该对象与方法的类型参数完全匹配

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

var res = RemoteToLocal<MostHatedPlace>(remoteObj); // MostHatedPlace derives from EntityBase
您知道代码中的这个分支是不可能到达的,因为有一个运行时检查可以防止您:

if (t == typeof(FavoritePlace)) {
    ....
}
但是,编译器必须假设可以到达此返回语句,这在
LOCAL\u TYPE
不是
FavoritePlace
的情况下是错误的

您可能需要在这里重新考虑泛型的使用:从代码段来看,您似乎需要泛型参数,以避免将结果类型转换为调用者中所需的类型。但是,调用方随后需要执行额外的检查,以查看
RemoteToLocal
中的转换是否成功。在本例中,一个方法

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

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

Derived1从Base继承,Derived2从Base继承。那么,你能把Derived1转换成Derived2吗?在您的示例中,Derived2是本地类型,Derived1是FavoritePlace,Base是EntityBase。强制转换操作符实际上可以执行一些完全不同的操作。它可以安全地强制转换为基类型(
FavoritePlace
→ <代码>EntityBase
),它还可以强制转换为派生类型(
EntityBase
LOCAL_TYPE
,这可能会引发异常),但它不能在一个步骤中从一个子类转换到另一个子类。更新了问题。关于泛型的使用:我需要它们将有关本地类型的信息传递给函数,函数用于决定执行哪个分支,以便构造正确的本地类型。但是,从某种意义上讲,您是对的,返回类型不必是泛型参数,也可以是EntityBase。显然,类型转换没有问题。谢谢你的好主意!我接受了另一个答案,因为它显示了如何摆脱这个问题,但你的答案也很有用,所以我给它+1.)
return new FavoritePlace(remoteObject as RemotePlaceType1);
if (t == typeof(FavoritePlace)) {
    ....
}
private EntityBase RemoteToLocal(RemoteObjectBaseType remoteObject) {
    ....
}