简体   繁体   中英

The type X cannot be used as type parameter T in the generic type Y

I don't see what is wrong with the following code, or how I can fix it. (Maybe I am misunderstanding generic types.)

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
}

Compiler complains that it cannot use X<I> as type parameter T in the generic type Y<T> .

Here is a 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; }
}

Notice the additional generic parameter I and constraints I have added to the definition of type Y .

Your initial definition of Y is too restrictive. C# makes a difference between ISomeInterface and any type implementing ISomeInterface .

Why is it so ?

The .NET compiler has a special way of handing generic types. For each generic type the compiler will create a separate type based on the generic type arguments, which is instead used during runtime. For example List<int> and List<string> will be completely different types, all exhibiting the behaviours defined by the List<_> generic type, but with the actual type int or string baked into the concrete type generated by the compiler.

When you define class Y<T> where T : X<ISomeInterface> you "seal" the generic parameter of X to be ISomeInterface . The compiler will accept any type inheriting X<ISomeInterface> but not X<SomethingElse> even if SomethingElse is itself an implementation of ISomeInterface . This is because the fragment where T : X<ISomeInterface> causes the ISomeInterface to be "baked in" within the type definition of Y<T> . That behaviour is expected and is a side effect of how generics are compiled to actual code. For the same reason one cannot do the following:

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

even though the type string inherits from object .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM