为什么通用类型定义实现的接口会丢失类型信息?

Mat*_*zer 9 .net c# generics reflection equality

例如,如果您运行以下代码...

Type IListType = new List<string>().GetType()
                                   .GetInterface("IList`1")
                                   .GetGenericTypeDefinition();
Run Code Online (Sandbox Code Playgroud)

...而且你看IListType变量,你会发现整个Type实例都有像FullName其他的一样可用的属性.

但是当你运行代码时会发生什么?

Type IListType2 = typeof(List<>).GetInterface("IList`1")
Run Code Online (Sandbox Code Playgroud)

现在IListType得到的泛型类型定义与第一个代码示例不同:大多数Type属性都将返回null.

这个问题的主要问题是IListType == IListType2它们是相同类型时不相等.

这是怎么回事?

这太丑了......

现在看看如果你打电话会发生什么IListType2.GetGenericTypeDefinition()......它恢复了类型信息!

这将是巨大的,一个.NET Framework开发团队成员可以解释我们为何已经奇怪的失去了它的元数据已经泛型类型定义具有IsGenericTypeDefinition属性设置为false同时它还是一个泛型类型定义,最后,如果你调用GetGenericTypeDefinition()就可以了,你恢复类型信息.

这很奇怪...

以下等式将是true:

Type IListType = new List<string>().GetType()
                        .GetInterface("IList`1")
                        .GetGenericTypeDefinition();

// Got interface is "like a generic type definition" since it has
// no type for T generic parameter, and once you call 
// GetGenericTypeDefinition() again, it recovers the lost metadata 
// and the resulting generic type definition equals the one got from
// List<string>!
Type IListType2 = typeof(List<>).GetInterface("IList`1").GetGenericTypeDefinition();

bool y = IListType == IListType2;
Run Code Online (Sandbox Code Playgroud)

usr*_*usr 7

以下类型都是不同的,并且没有通过继承关系连接:

  • IList<T>
  • IList<int>
  • IList<string>

所有这些都有不同的Type对象,因为你可以用它们做不同的事情.后两者是前者的专业.第一个是泛型​​类型定义(您可以通过它获得GetGenericTypeDefinition).

解释还有另一部分.当你说class List<T> : IList<T>那个IList<T>部分等于typeof(IList<>)因为它已经专门化了T.这不再是泛型类型定义.它是一种具体的类型IList<int>.这是一家专业以它唯一的类型参数绑定到TList<T>是专门给.


LINQPad实验:

Type bound = new List<string>().GetType().GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //string


Type bound = typeof(List<>).GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //"T"
(bound.GenericTypeArguments.Single() == typeof(List<>).GetGenericArguments().Single()).Dump(); //true
Run Code Online (Sandbox Code Playgroud)

  • @MatíasFidemraizer不,他们被绑定到了List的T.他们不再可以自定义.如果你实现了多个这样的接口,它们将具有相同的类型参数,这是它们绑定的证据.在任何情况下,当您调用`GetGenericTypeDefinition`时,这将转换回定义.@MatíasFidemraizer你可以检查这是否回答了你的问题?在我看来它确实如此. (2认同)