2013-08-22 5 views
2

Недавно я столкнулся с интересным поведением наследования типа C# generic. Представьте себе следующий пример:Дополнительный тип в наследовании открытых общих типов в C#

class Foo<T> {} 

class Bar<T> : Foo<T> {} 

Когда мы используем замкнутые родовые типы, их поведение с точки зрения наследования является довольно очевидно:

Console.WriteLine(typeof(Bar<int>).BaseType == typeof(Foo<int>)); // True 

Но когда мы используем открытые универсальные типы, мы получаем следующее:

Console.WriteLine(typeof(Bar<>).BaseType == typeof(Foo<>)); // False 

Лично я ожидал, что эта строка будет распечатана True. Итак, давайте посмотрим на базовый тип Bar<>:

Action<Type> discoverType = type => 
    { 
     Console.WriteLine("Type name: " + type.ToString()); 

     Console.WriteLine("Is generic type definition: " + 
      type.IsGenericTypeDefinition); 

     Console.WriteLine("Generic ags: " + 
      string.Join<Type>(", ", type.GetGenericArguments())); 

     Console.WriteLine("Types in generic:" + 
      string.Join<Type>(", ", type.GenericTypeArguments)); 

     Console.WriteLine(Environment.NewLine); 
    }; 

Type baseType = typeof(Bar<>).BaseType; 
discoverType(baseType); 

Type openType = baseType.GetGenericTypeDefinition(); 
discoverType(openType); 

Линии выше производить следующий вывод:

Type name: GenericsReflection.Program+Foo`1[T] 
Is generic type definition: False 
Generic ags: T 
Types in generic:T 


Type name: GenericsReflection.Program+Foo`1[T] 
Is generic type definition: True 
Generic ags: T 
Types in generic: 

Так вот у нас есть тип (первый), который был создан из Foo<T> (второй), заменив T на T (необычный, но действительный, так как T также является созданным во время выполнения). Если у нас есть еще один тип, который наследуется от Foo<T>, то новый базовый тип будет сгенерирован:

class Another<T> : Foo<T> { } 

Console.WriteLine(typeof(Another<>).BaseType == typeof(Bar<>).BaseType); // False 

Итак, мой вопрос: зачем нам эти «прокси» типы между Bar<> и Foo<> и между Another<> и Foo<>, почему открытые общие типы не могут быть унаследованы друг от друга?

ответ

3

Яснее, если вы укажете два типа параметров по-разному - T1 и T2, например. Тогда разница становится яснее:

Type name: Foo`1[T2] 
Is generic type definition: False 
Generic ags: T2 
Types in generic:T2 


Type name: Foo`1[T1] 
Is generic type definition: True 
Generic ags: T1 
Types in generic: 

Они действительно разные - typeof(Bar<>).BaseType имеет тип аргументов, указанных * по Bar<>) - это просто, что вам нужно Bar<> сама, чтобы быть конкретным, прежде чем вы получите конкретный Foo<>. Другими словами, typeof(Bar<>).BaseType - это , построенный, тогда как typeof(Foo<>) - нет. См. Type.IsConstructedGenericType для получения дополнительной информации об этом (это другое свойство, которое даст разные значения для двух типов).

Иными словами, рассмотрим эти три декларации:

class X1 : Foo<string> {} 
class X2<T> : Foo<string> {} 
class X3<TKey, TValue> : Foo<TKey> {} 
class X4<TKey, TValue> : Foo<TValue> {} 

Вы бы ожидать, базовый тип каждого из этих типов, чтобы быть таким же, как typeof(Foo<>)? В первом и втором случаях, конечно, это Foo<string>, а не Foo<> ... так почему вы ожидаете, что он будет другим, потому что он использует параметр типа вместо конкретного типа?

+0

Джон, спасибо за объяснение, теперь у меня это есть. Я просто ожидал, что базовый класс универсального определения 'X2',' X3', 'X4' будет' Foo <> '. Но теперь мне кажется, что этот базовый класс должен передавать аргументы типа из 'Bar ' в 'Foo '. – takemyoxygen