什么是Type.GUID以及它与Type.Equals()的关系?

Rob*_*Rob 11 c# generics types runtime equals

在尝试比较System.RuntimeType泛型类型的实例时,我遇到了一些有趣的行为TOut:

Type runtimeT = methodInfo.ReturnType; // get RuntimeType using reflection
Type genericT = typeof(TOut);

// This condition fails because runtimeT doesn't 
// seem to include an assembly qualified name
if(runtimeT.Equals(genericT)) { ... }
Run Code Online (Sandbox Code Playgroud)

这是我的证据:

 debug watch window的屏幕截图 -  Equals()在类型上返回false,在GUID上返回true

免责声明:我不确切知道GUR在CLR /类型系统的上下文中是什么,当然除了首字母缩略词代表全局唯一标识符.也许这个名字误导了我.

假设:我假设TypeGUID唯一地标识完全限定类型,包括屏幕截图中AssemblyQualifiedName缺少的类型factoryInfo.ReturnType(null值).

我的假设错了吗?

  • 是的: GUID类型真正代表什么,它是如何使用的?

  • 否: 为什么不Equals()通过比较GUID来实现?

Eri*_*ert 22

为了扩展Jared的(完全正确的)答案:

在COM世界中,每个接口都由全局唯一标识符标识.在COM中没有"改变"接口这样的东西; 接口必须永远相同.相反,您创建一个新的界面并为其提供一个新的GUID.任何两个不同的接口都需要具有不同的GUID.接口相等性在COM中定义为GUID相等.

在.NET世界中,类型相等更复杂.一种类型与特定组件相关联.但不仅如此!如果你加载相同的程序集两次(例如,一次由它的程序集名称和一次它的磁盘位置)并要求两个程序集"相同"类型,你将得到两个不同的类型对象,它们将不会相等,即使显然他们有相同的GUID.

显然这是一个重要的出发点; .NET和COM在这方面完全不兼容.互操作必须发生时会发生什么?不知何故,COM和.NET必须就如何在相同的过程中进行比较时如何比较类型的规则达成一致.(因为.NET正在调用COM代码,反之亦然.)

因此,您可以在.NET中执行的操作是"此类型与此GUID相关联".当COM规则适用时,COM代码将通过比较GUID来比较两种类型的相等性,因为这就是COM世界中的相等意义.

在.NET中,使用.NET的常规规则比较类型的相等性.

这在共同场景中呈现出显着的潜在问题.假设您编写了一个与大型复杂COM库互操作的.NET程序.只是为了选择一个完全非随机的例子,假设你已经为Word写了一个托管扩展,它有一个绝对巨大的COM"表面区域".此表面区域通过主互操作程序集暴露给.NET世界,主要互操作程序集包含"虚拟"类型,这些类型与COM世界中的核心响应接口具有所有相同的GUID.然后可以编写.NET代码以通过"虚拟"对象与COM层进行通信,这些对象看起来像适当的接口类型的对象,并且将.NET代码视为适当的.NET类型的对象.

所以这很好用.然后,您将.NET库发送给客户,并且您意识到Word不会自动将PIA发送给客户.相反,需要运送他们的PIA.这是巨大的.

因此诞生了C#4的"无PIA"功能.在C#4中,您可以生成一个Word扩展,只生成它实际使用的单词PIA部分的内部副本.这通常要小得多.然后,您可以重新分发扩展库,而无需重新分发大型PIA.

但这立刻就出现了问题.假设有两个这样的库,他们想在PIA中使用两者共有的接口类型相互通信?从.NET的角度来看,类型是按装配; 从COM的角度来看,每个库中PIA类型的副本是相同的,但 .NET的观点不同.

因此我们在v4 CLR中添加了一个特殊功能.在这种情况下,在两个不同的组件中的两种类型(和PIA类型,如果是本!)都统一由CLR和视为由GUID相等,匹配COM行为.

当然,细节要比简单的草图复杂得多.我的观点很简单,就是你在这里开了一大堆蠕虫; GUID如何与类型相等相互作用是一个深层而棘手的主题,很少有人能够完全理解.


Jar*_*Par 13

Type.GUID不用作比较的一个原因是Equals它是用户可控制的项目.例如,我可以通过执行以下操作来决定GUIDinterface

[Guid("2bfd006d-94b9-43af-843f-5b32f7567086")]
interface IFoo { ... }
Run Code Online (Sandbox Code Playgroud)

这对于生成COM互操作的接口是必要的.如果Equals在依赖GUID是唯一的一个类型,然后给定的开发者可以通过给自己的类型相同的系统造成严重破坏GUID的说string,int等...