我无法将一个泛型类型转换为另一个泛型类型,除了转换应该是有效的
我要归档的内容很简单(对于 MyModel
实现 IModel
和 MyImplementation
实现 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/