简体   繁体   English

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

[英]What is Type.GUID and how does it relate to Type.Equals()?

I came across some interesting behavior while trying to compare an instance of System.RuntimeType with a generic type TOut : 尝试将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)) { ... }

Here is my evidence: 这是我的证据:

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

Disclaimer: I don't know precisely what a GUID is in the context of the CLR / type-system, except of course that the acronym stands for global unique identifier . 免责声明:我不确切知道GUR在CLR /类型系统的上下文中是什么,当然除了首字母缩略词代表全局唯一标识符 Perhaps the name is misleading me. 也许这个名字误导了我。

Assumption: I'm assuming here that a Type GUID uniquely identifies the fully qualified type, including the AssemblyQualifiedName that's missing from factoryInfo.ReturnType in the screenshot (the null value.) 假设:我假设Type GUID唯一标识完全限定类型,包括截屏中的factoryInfo.ReturnType中缺少的AssemblyQualifiedNamenull值)。

Is my assumption wrong? 我的假设错了吗?

  • Yes: What does type GUID truly represent, and how is it used? 是的: GUID类型真正代表什么,它是如何使用的?

  • No: Why wouldn't Equals() be implemented by comparing GUID? 否:为什么不通过比较GUID来实现Equals()

To expand a bit upon Jared's (entirely correct) answer: 为了扩展Jared的(完全正确的)答案:

In the COM world every interface is identified by a globally unique identifier. 在COM世界中,每个接口都由全局唯一标识符标识。 There is no such thing as "changing" an interface in COM; 在COM中没有“改变”接口的东西; interfaces are required to be the same forever. 接口必须永远相同。 Instead, you create a new interface and give it a new GUID. 相反,您创建一个新的界面并为其提供一个新的GUID。 Any two interfaces that differ are required to have different GUIDs. 任何两个不同的接口都需要具有不同的GUID。 Interface equality is defined as GUID equality in COM. 接口相等性在COM中定义为GUID相等。

In the .NET world, type equality is more complicated. 在.NET世界中,类型相等更复杂。 A type is associated with a particular assembly, for one thing. 一种类型与特定组件相关联。 But not just that! 但不仅如此! If you load the same assembly twice (say, once by its assembly name and once by its disk location) and ask the two assemblies for "the same" type, you will get two different type objects and they will not compare as equal even though obviously they have the same GUID. 如果你加载相同的程序集两次(例如,一次由它的程序集名称和一次它的磁盘位置)并要求两个程序集“相同”类型,你将得到两个不同的类型对象,它们将不会相等,即使显然他们有相同的GUID。

Clearly this is a major point of departure; 显然这是一个重要的出发点; .NET and COM are deeply incompatible in this regard. .NET和COM在这方面完全不兼容。 What happens when interop must occur? 互操作必须发生时会发生什么? Somehow COM and .NET have got to agree on some rules for how types are compared for equality when both are in play in the same process. 不知何故,COM和.NET必须就如何在相同的过程中进行比较时如何比较类型的规则达成一致。 (Because .NET is calling COM code, or vice versa.) (因为.NET正在调用COM代码,反之亦然。)

Thus what you can do in .NET is say "this type is associated with this GUID". 因此,您可以在.NET中执行的操作是“此类型与此GUID相关联”。 When COM rules apply, the COM code will compare two types for equality by comparing GUIDs, because that's what equality means in the COM world. 当COM规则适用时,COM代码将通过比较GUID来比较两种类型的相等性,因为这就是COM世界中的相等意义。

In .NET, types are compared for equality using the usual rules for .NET. 在.NET中,使用.NET的常规规则比较类型的相等性。

This then presents a significant potential problem in a common scenario. 这在共同场景中呈现出显着的潜在问题。 Suppose you have written a .NET program which interoperates with a large, complex COM library. 假设您编写了一个与大型复杂COM库互操作的.NET程序。 Just to pick a completely non-random example, suppose you've written a managed extension to Word, which has an absolutely enormous COM "surface area". 只是为了选择一个完全非随机的例子,假设你已经为Word编写了一个托管扩展,它有一个绝对巨大的COM“表面区域”。 This surface area is exposed to the .NET world via a Primary Interop Assembly, which contains "dummy" types that have all the same GUIDs as the corersponding interfaces in the COM world. 此表面区域通过主互操作程序集暴露给.NET世界,主要互操作程序集包含“虚拟”类型,这些类型与COM世界中的核心响应接口具有所有相同的GUID。 The .NET code can then be written to talk to the COM layer via the "dummy" objects, which look to COM like objects of the appropriate interface type, and look to .NET code to be objects of the appropriate .NET type. 然后可以编写.NET代码以通过“虚拟”对象与COM层进行通信,这些对象看起来像适当的接口类型的对象,并且将.NET代码视为适当的.NET类型的对象。

So that works just fine. 所以这很好用。 And then you go to ship your .NET library to customers and you realize Word does not ship the PIA to customers automatically . 然后,您将.NET库发送给客户,并且您意识到Word不会自动将PIA发送给客户 Rather, you are required to ship their PIA. 相反, 需要运送他们的PIA。 Which is enormous. 这是巨大的。

Thus was born the "no PIA" feature of C# 4. In C# 4 you can generate a Word extension that makes an internal copy of only the portions of the word PIA that it actually uses . 因此诞生了C#4的“无PIA”功能。在C#4中,您可以生成一个Word扩展, 只生成它实际使用的单词PIA部分的内部副本。 Which is typically much smaller. 这通常要小得多。 You can then redistribute your extension library without redistributing the large PIA. 然后,您可以重新分发扩展库,而无需重新分发大型PIA。

But this immediately presents a problem. 但这立刻就出现了问题。 Suppose there are two such libraries, and they want to communicate with each other using the interface types that are common to both, in the PIA ? 假设有两个这样的库,他们想在PIA中使用两者共有的接口类型相互通信? From the .NET perspective, types are per-assembly; 从.NET的角度来看,类型是按装配; the copies of the PIA types in each library are the same from COM's point of view, but different from .NET's point of view. 从COM的角度来看,每个库中PIA类型的副本是相同的,但 .NET的观点不同

Therefore we added a special feature in the v4 CLR. 因此我们在v4 CLR中添加了一个特殊功能。 In that situation, the two types in the two different assemblies (and the PIA type, if it is present!) are unified by the CLR and are treated as equal by GUID, matching the COM behaviour. 在这种情况下,在两个不同的组件中的两种类型(和PIA类型,如果是本!)由CLR 统一视为由GUID相等,匹配COM行为。

The details of course are much more complex than that simple sketch. 当然,细节要比简单的草图复杂得多。 My point is simply that you are opening an enormous can of worms here; 我的观点很简单,就是你在这里开了一大堆蠕虫; how GUIDs interact with type equality is a deep and tricky subject that few people understand fully. GUID如何与类型相等相互作用是一个深层而棘手的主题,很少有人能够完全理解。

One reason that Type.GUID isn't used as the comparison for Equals is that it's user controllable item. Type.GUID未用作Equals的比较的一个原因是它是用户可控制的项目。 For example i can dictate the GUID of my interface by doing the following 例如,我可以通过执行以下interface来指定我的interfaceGUID

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

This is necessary in order to produce interfaces for COM interop. 这对于生成COM互操作的接口是必要的。 If Equals relied on the GUID being unique to a type then a given developer could wreak havoc on the system by giving their type the same GUID as say string , int , etc ... 如果Equals依赖于GUID对于某个类型是唯一的,那么给定的开发人员可以通过为其类型提供与stringint等相同的GUID来对系统造成严重破坏......

You shouldn't really rely on System.Type's GUID property for Type comparison. 您不应该真正依赖System.Type的GUID属性进行类型比较。 Especially in inter-process communication (WCF, Remoting) , the Guid may not be the same (unless it's manually specified as in JaredPar's example). 特别是在进程间通信(WCF,Remoting)中,Guid可能不一样(除非它在JaredPar的例子中手动指定)。

Internally, Type.Equals uses a RuntimeTypeHandle for equality comparison. 在内部,Type.Equals使用RuntimeTypeHandle进行相等性比较。

I'm not sure why your equality comparison above is failing. 我不确定为什么你上面的平等比较失败了。 It shouldn't. 它不应该。 In the very simple example below, equal returns true . 在下面这个非常简单的例子中,equal返回true

    static void Main(string[] args)
    {
        Test<object>();
    }

    static object Test<T>()
    {
        var currentMethod = ((MethodInfo) MethodBase.GetCurrentMethod());
        var oType = currentMethod.ReturnType;
        var genericType = typeof (T);
        var equal = oType.Equals(genericType); // result is true.
        return null;
    }

My random shot in the dark guess is that you're using Entity Framework with Proxy Creation Enabled? 我在黑暗猜测中随机拍摄的是您正在使用启用了代理创建的实体框架吗? In which case, generic parameter T of IEntitySet is a dynamically generated type that Entity Framework has created for you... If this is the case, you should get the desired result by comparing the generic arguments individually: 在这种情况下,IEntitySet的泛型参数T是Entity Framework为您创建的动态生成的类型...如果是这种情况,您应该通过单独比较泛型参数来获得所需的结果:

A GUID is randomly generated sequence of bytes (16 by default) that is semi-guaranteed to never be repeated - not across computers or time. GUID是随机生成的字节序列(默认为16),半保证永远不会重复 - 不是跨计算机或时间。 Semi-guaranteed because the possibility to repeat does exist but it's so minuscule it is not considered. 半保证,因为重复的可能性确实存在,但它是如此微小,不被考虑。

Because of this, most programmers use GUIDs when they need to provide an ID to something where they worry about the ID having a collision against another ID that may end up existing in the same realm (IDs of programs running, or of table rows or a million other things) 因此,大多数程序员在需要提供ID时会使用GUID,因为他们担心ID会与同一领域中可能最终存在的另一个ID发生冲突(运行的程序的ID,或表行或百万其他的东西)

But in short, you can think of a GUID as a random-ish number that represents an ID, is 16 bytes long and won't ever be generated twice. 但简而言之,您可以将GUID视为表示ID的随机数字,长度为16个字节,并且不会生成两次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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