c# - 通用类型转换失败

标签 c# generics casting

我无法将一个泛型类型转换为另一个泛型类型,除了转换应该是有效的

我要归档的内容很简单(对于 MyModel 实现 IModelMyImplementation 实现 IImplementation):

IImplementation<IModel> implementation = new MyImplementation<MyModel>();
Assert.IsNull(implementation as IImplementation<IModel>);

这有点令人困惑,因为类型应该是有效的。

完整的概念模型:

interface IModel {}

class MyModel : IModel {}

interface IImplementation<TModel> where TModel : IModel { }

class MyImplementation<TModel> : IImplementation<TModel>
    where TModel : IModel { }

public void CallRegister()
{
    var implementation = new MyImplementation<MyModel>();
    var instance = CastModel(implementation);
    Assert.IsNotNull(instance); //this assert fails!
}

private object CastModel<TModel>(IImplementation<TModel> implementation) where TModel : IModel
{
    return implementation as IImplementation<IModel>;
}

我需要这个 Actor 才能保存多个 IImplementation s 相同 Dictionary<Type, IImplementation<IModel>> ,其中 key 是通过执行 typeof(TModel) 获得的. 为了保证这种类型的安全,我不想使用 Dictionary<Type, object> .

  • 为什么转换失败?是否有其他资源?它与 Invalid Cast of Type Constrained C# Generic 类似的问题, 但没有解释为什么它不起作用。
  • 如果无法进行这种强制转换,那么归档类似于上述字典的功能的最佳方法是什么?

最佳答案

尽管 Olivier 的回答说明了为什么这通常会出错,但有一种方法可以使它在您的程序中起作用。

您想要的功能称为通用接口(interface)协变。协方差是如果 Cat是一个 Animal , 然后是 IFoo<Cat>是一个 IFoo<Animal> .

C# 中的协变仅适用于以下情况:

  • “外部”类型是接口(interface)、委托(delegate)或数组。没有类或结构。
  • 如果是接口(interface)或委托(delegate),该类型必须在编译时标记为支持协变。数组免费获得(不安全!)协方差。
  • “内部”类型——变化的类型——都是引用类型。你不能说 IFoo<int>是一个 IFoo<object>即使 int是一个 object ,因为它们不是两种引用类型。

要将接口(interface)标记为协变,您可以输入 out在您希望允许变化的类型参数声明之前:

interface IImplementation<out TModel> where TModel : IModel { }

如果你这样做,你的程序就会开始工作。

但是out提醒您协方差只有在 T 时才是安全的用于输出位置。这是合法的:

interface I<out T> {
  T M();
}

这不是:

interface I<out T> {
  void M(T t);
}

首先,T 仅从事物中传递出来。在第二个中,它通过 in 传递。

在第一种情况下,我们不能使用协方差来引入类型空洞。我们有一个 I<Cat>我们将其转换为 I<Animal> ,现在 M返回 Animal , 但没关系,因为我们已经知道它将返回 Cat , 和一个 Cat是一个 Animal .

但在第二种情况下,我们有相反的情况。如果我们允许 I<Cat>转换为 I<Animal>然后我们有一个 M可以采取 Turtle , 但真正的实现只能处理 Cat秒。这就是 C# 将其设为非法的原因。

所以继续使用协变,但请记住,您必须向编译器证明您需要它,并且它在所有情况下都是安全的。如果您不想要它,或者它不安全,那么您就没有协方差,您将不得不为您的问题找到不同的解决方案。

关于c# - 通用类型转换失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43378173/

相关文章:

c# - 执行后处置ReactiveCommand

c# - 委托(delegate)方法或抽象类

python - 有没有更优雅的方法在Python中将整数列表转换为WORD(C_Types)数组

c# - 正则表达式获取 C# 中模式的所有可能匹配项

c# - 要实现什么 Web 服务以便从 iphone 应用程序中轻松读取?

java - 什么是原始类型,为什么我们不应该使用它呢?

java - 在这个 Java 类层次结构中,如何使用泛型来避免类型转换?

swift - 如何使用泛型推断类型?

c# - 有没有借口从隐式转换中抛出异常?

c# - 在 C# 中将类型转换为对象