【问题标题】:Conversion of constrained generic params from subtype to supertype将受约束的泛型参数从子类型转换为超类型
【发布时间】:2013-01-27 12:17:48
【问题描述】:

我有一个这样的通用函数:

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 呢? 不是可转换为关系传递的吗?

【问题讨论】:

  • Derived1 继承自 Base,Derived2 继承自 Base。那么,你能把Derived1转换成Derived2吗?在您的示例中,Derived2 是 LOCAL_TYPE,Derived1 是 FavoritePlace 并且 Base 是 EntityBase.
  • 强制转换运算符实际上可以执行一些非常不同的操作。它可以安全地转换为基本类型(FavoritePlace → EntityBase),也可以转换为派生类型(EntityBase → LOCAL_TYPE,这可能会引发异常),但它不能从一个转换一步子类化为另一个。

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


【解决方案1】:

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

class OtherEntity : EntityBase { }

那么你在调用时不能返回FavoritePlace

var entity = RemoteToLocal<OtherEntity>(remoteObject);

如果您知道转换是安全的,您可以通过强制转换绕过它:

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

【讨论】:

  • 我接受了另一个答案,因为它展示了如何完全摆脱这个问题,但你的答案也很有用,所以我给它+1。 :)
【解决方案2】:

虽然您已经通过运行时代码确定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 不是 FavoritePlace,这将是一个错误。

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

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

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

【讨论】:

  • 更新了问题。关于泛型的使用:我需要它们将有关本地类型的信息传递给函数,该函数用于决定采用哪个执行分支,以便构造正确的本地类型。但是,从某种意义上说,您是对的,返回类型不必是该通用参数,而可能只是 EntityBase。那么类型转换显然没有问题。谢谢你的好主意!
猜你喜欢
  • 2012-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多