类型X不能用作泛型类型Y中的类型参数T.

问题描述 投票:2回答:1

我没有看到以下代码有什么问题,或者我如何解决它。 (也许我误解了泛型类型。)

class X<I>
   where I : ISomeInterface
{ }

class Y<T>
   where T : X<ISomeInterface>
{ }

class Z<I>
   where I : ISomeInterface
{
   Y<X<I>> AData { get; } // What compiler does not like
   Y<X<ISomeInterface>> BData { get; } // What compiler likes
}

编译器抱怨它不能在通用类型X<I>中使用T作为类型参数Y<T>

c# .net generics interface covariance
1个回答
4
投票

这是一个working solution

interface ISomeInterface {}

class X<I>
   where I : ISomeInterface
{ }

class Y<T, I>
   where T : X<I>
   where I : ISomeInterface
{ }

class Z<I>
   where I : ISomeInterface
{
   Y<X<I>, I> MyOtherData { get; set; }
   Y<X<ISomeInterface>, ISomeInterface> MyData { get; set; }
}

注意我添加到类型I的定义中的附加通用参数Y和约束。

您对Y的初始定义过于严格。 C#在ISomeInterface和任何实现ISomeInterface的类型之间有所不同。

为什么会这样?

.NET编译器有一种处理泛型类型的特殊方法。对于每种泛型类型,编译器将基于泛型类型参数创建单独的类型,而不是在运行时使用。例如,List<int>List<string>将是完全不同的类型,所有类型都展示了由List<_>泛型类型定义的行为,但实际类型为intstring,这些类型被编译器生成的具体类型。

当你定义class Y<T> where T : X<ISomeInterface>时,你将X的通用参数“密封”为ISomeInterface。编译器将接受继承X<ISomeInterface>而不是X<SomethingElse>的任何类型,即使SomethingElse本身是ISomeInterface的实现。这是因为片段where T : X<ISomeInterface>导致ISomeInterfaceY<T>的类型定义中被“烘焙”。这种行为是预期的,并且是泛型如何编译为实际代码的副作用。出于同样的原因,人们不能做到以下几点:

List<object> x = new List<string>();

即使string类型继承自object

© www.soinside.com 2019 - 2024. All rights reserved.