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

时间:2022-06-11 18:54:48

For example, if you run the following code...

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

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

...and you watch IListType variable, you'll find that the whole Type instance has all properties available like FullName and others.

...并且您观察IListType变量,您会发现整个Type实例具有FullName等所有可用属性。

But what happens when you run the code bellow?

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

Type IListType2 = typeof(List<>).GetInterface("IList`1")

Now IListType got from a generic type definition isn't the same as the first code sample: most Type properties will return null.

现在,来自泛型类型定义的IListType与第一个代码示例不同:大多数Type属性将返回null。

The main issue with this is that IListType == IListType2 doesn't equal while they're the same type.

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

What's going on?

这是怎么回事?

This is ugly...

Now see what happens if you call IListType2.GetGenericTypeDefinition()... It recovers the type information!

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

It would be great that a .NET Framework development team member could explain us why an already generic type definition which has strangely lost its metadata has IsGenericTypeDefinition property set to false while it's still a generic type definition, and finally, if you call GetGenericTypeDefinition() on it, you recover the type information.

.NET Framework开发团队成员可以解释为什么一个奇怪地丢失其元数据的已经泛型的类型定义为什么IsGenericTypeDefinition属性设置为false,而它仍然是泛型类型定义,最后,如果你调用GetGenericTypeDefinition()在它上面,你恢复了类型信息。

This is strange...

The following equality will be 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;

2 个解决方案

#1


7  

The following types are all different and not connected by an inheritance relationship:

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

  • IList<T>
  • 的IList
  • IList<int>
  • 的IList
  • IList<string>
  • 的IList <字符串>

All of these have different Type objects because you can do different things with them. The latter two are the specializations of the former. The first is the generic type definition (which you can obtain through GetGenericTypeDefinition).

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

There is another part to the explanation. When you say class List<T> : IList<T> then the IList<T> part is not equal to typeof(IList<>) because it is already specialized to T. This is no longer a generic type definition. It is a concrete type such as IList<int>. It is specialized to bind its only type argument to the T that List<T> was specialized to.

解释还有另一部分。当你说类List :IList 时,IList 部分不等于typeof(IList <>),因为它已经专门用于T.这不再是泛型类型定义。它是一种具体的类型,如IList 。它专门用于将其唯一的类型参数绑定到List 专用的T。


Experiment for LINQPad:

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

#2


2  

The first version of IList<T> is the actual typed version of IList<T>, let's say IList<string>.

IList 的第一个版本是IList 的实际类型版本,比如说IList

The second one is the generic definition of IList<T> without a type for T.

第二个是IList 的通用定义,没有T的类型。

That makes the two interfaces different. There are not the same, since the first is a concrete version of the second.

这使得两个接口不同。有不一样的,因为第一个是第二个的具体版本。

#1


7  

The following types are all different and not connected by an inheritance relationship:

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

  • IList<T>
  • 的IList
  • IList<int>
  • 的IList
  • IList<string>
  • 的IList <字符串>

All of these have different Type objects because you can do different things with them. The latter two are the specializations of the former. The first is the generic type definition (which you can obtain through GetGenericTypeDefinition).

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

There is another part to the explanation. When you say class List<T> : IList<T> then the IList<T> part is not equal to typeof(IList<>) because it is already specialized to T. This is no longer a generic type definition. It is a concrete type such as IList<int>. It is specialized to bind its only type argument to the T that List<T> was specialized to.

解释还有另一部分。当你说类List :IList 时,IList 部分不等于typeof(IList <>),因为它已经专门用于T.这不再是泛型类型定义。它是一种具体的类型,如IList 。它专门用于将其唯一的类型参数绑定到List 专用的T。


Experiment for LINQPad:

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

#2


2  

The first version of IList<T> is the actual typed version of IList<T>, let's say IList<string>.

IList 的第一个版本是IList 的实际类型版本,比如说IList

The second one is the generic definition of IList<T> without a type for T.

第二个是IList 的通用定义,没有T的类型。

That makes the two interfaces different. There are not the same, since the first is a concrete version of the second.

这使得两个接口不同。有不一样的,因为第一个是第二个的具体版本。