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

C# 什么是Type.GUID以及它与Type.Equals()的关系如何?,c#,generics,types,runtime,equals,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 n

我在尝试将
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)) { ... }
以下是我的证据:

免责声明:我不知道CLR/type系统上下文中的GUID是什么,当然首字母缩写表示全局唯一标识符除外。也许这个名字误导了我

假设:我在这里假设
类型
GUID唯一标识完全限定的类型,包括屏幕截图中
factoryInfo.ReturnType
中缺少的类型(值
null

我的假设错了吗

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

  • 否:为什么不通过比较GUID来实现


GUID是随机生成的字节序列(默认为16个字节),半保证不会重复—不会跨计算机或时间重复。半保证,因为重复的可能性确实存在,但它是如此微小,因此没有考虑

正因为如此,大多数程序员在需要为某些内容提供ID时都会使用GUID,他们担心该ID与另一个可能最终存在于同一领域的ID(运行的程序的ID、表行的ID或其他一百万个ID)发生冲突


但简而言之,您可以将GUID视为表示ID的随机数字,长度为16字节,并且不会生成两次。

没有将
Type.GUID
用作
Equals
的比较的一个原因是它是用户可控制的项。例如,我可以通过执行以下操作来指定我的
接口的
GUID

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

这是为COM互操作生成接口所必需的。如果
Equals
依赖于类型所特有的
GUID
,那么给定的开发人员可能会给他们的类型提供与字符串、int
等相同的
GUID
,从而对系统造成严重破坏…

您不应该真正依赖system.type的GUID属性进行类型比较。特别是在进程间通信(WCF、远程处理)中,Guid可能不同(除非像JaredPar的示例中那样手动指定)

在内部,Type.Equals使用RuntimeTypeHandle进行相等比较

我不知道为什么你上面的平等比较失败了。不应该。在下面非常简单的示例中,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;
    }
static void Main(字符串[]args)
{
Test();
}
静态对象测试()
{
var currentMethod=((MethodInfo)MethodBase.GetCurrentMethod());
var oType=currentMethod.ReturnType;
变量genericType=类型(T);
var equal=oType.Equals(genericType);//结果为true。
返回null;
}

我在黑暗中随机猜测,您使用的是启用代理创建的实体框架?在这种情况下,IEntitySet的泛型参数T是实体框架为您创建的动态生成的类型。。。如果是这种情况,您应该通过单独比较泛型参数来获得所需的结果:

要在Jared(完全正确)的答案上展开一点:

在COM世界中,每个接口都由一个全局唯一标识符标识。COM中没有“更改”接口这样的事情;接口要求永远相同。相反,您可以创建一个新接口并为其提供一个新的GUID。任何两个不同的接口都需要有不同的guid。接口相等在COM中定义为GUID相等

在.NET世界中,类型平等更为复杂。一方面,类型与特定程序集相关联。但不仅仅如此!如果加载同一程序集两次(一次按其程序集名称加载,一次按其磁盘位置加载),并要求两个程序集使用“相同”类型,则会得到两个不同的类型对象,即使它们显然具有相同的GUID,它们也不会进行相同的比较

显然,这是一个主要的出发点。NET和COM在这方面极不兼容。当必须进行互操作时会发生什么情况?不知何故,COM和.NET在同一过程中,就如何比较类型以获得相等性达成了一些规则。(因为.NET正在调用COM代码,反之亦然。)

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

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

然后,这在一个常见场景中提出了一个重要的潜在问题。假设您编写了一个.NET程序,该程序可以与大型复杂的COM库进行互操作。举一个完全非随机的例子,假设您已经为Word编写了一个托管扩展,它有一个绝对巨大的COM“表面积”。该表面积通过一个主互操作程序集暴露给.NET世界,该程序集包含“虚拟”类型,这些类型与COM世界中的corersponding接口具有所有相同的GUID。然后可以编写.NET代码,通过“虚拟”对象与COM层对话,这些对象看起来像是具有适当接口类型的COM类对象,而.NET代码看起来像是具有适当.NET类型的对象

这样就可以了。然后,您将.NET库发送给客户,您会发现Word不会自动将PIA发送给客户。相反,您需要发送他们的PIA。这是巨大的

C#4的“无PIA”特征由此诞生。在C#4中,您可以生成一个单词扩展名,该扩展名只生成单词PIA实际使用部分的内部副本。它通常要小得多。然后,您可以在不使用r的情况下重新分发扩展库