为什么类型System .__ ComObject声称(有时)不公开?

时间:2013-08-06 21:01:07

标签: c# .net reflection encapsulation cil

当我反思所有类型时,碰巧发现了一些奇怪的事情,以便出于好奇而检查其他内容。

为什么大会System.__ComObject的班级mscorlib.dll(有时?)声称是公开的,而事实上它似乎是非公开的?如果我在一个简单的C#控制台应用程序中运行以下代码:

var t = Type.GetType("System.__ComObject");
Console.WriteLine(t.IsPublic);   // "True"   ?!
Console.WriteLine(t.IsVisible);  // "False"

输出似乎有冲突。非嵌套类型(t.IsNested为false)应为IsPublicIsVisible提供相同的真值。当我用IL DASM查看程序集时,我看到了:

.class private auto ansi beforefieldinit System.__ComObject
       extends System.MarshalByRefObject
{
} // end of class System.__ComObject

对我来说,它看起来非常像非公开的类,这些对应于下面的C#代码:

namespace System
{
    // not public
    internal class __ComObject : MarshalByRefObject
    {
        ...
    }
}

当我与具有相似名称System.__Canon和类似IL修饰符的其他类型进行比较时,IsPublicIsVisible都会按预期返回false。

有谁知道为什么(以及何时)Type.GetType("System.__ComObject").IsPublic给出了真的?

1 个答案:

答案 0 :(得分:10)

__ComObject的{​​p> Mono's implementation可能会提供一些线索。它确实被声明为 internal ,但评论说“它没有公共方法,它的功能通过System.Runtime.InteropServices.Marshal公开。我没有挖掘Marshal,但我认为它负责GetType()的实施,因此它也可以自定义IsPublic属性。

根据我的经验,Type.GetType("System.__ComObject").IsPublic始终是true。关于GetType("System.Net.Mail.MSAdminBase"),我认为它是通过customized primary interop assembly公开的COM类,其中可以明确控制类型的可见性(尽管这只是我的想法,没有进行任何研究)。

<强> [UPDATE]

我收到了latest Framework source code,发现我错误地认为IsPublic类型的__ComObject属性的自定义由Marshal完成。实际上,它是由非托管代码完成的。 Object.GetType()在Object.cs中定义如下:

[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern Type GetType(); 

.NET 4.x中实现的非托管源代码不可用,但.NET 2.0版本为available。在.NET 2.0中有一个excellent answer关于Object.GetType的实现。我只是添加,IsPublicSystem.Runtime.InteropServices._Type接口定义,System.Type派生自System.Type,并且可以被任何Object.GetType - 后代类覆盖。显然,ObjectNative::GetClass返回了这样一个类的实现,这发生在if (!objRef->IsThunking()) refType = typeHandle.GetManagedClassObject(); else refType = CRemotingServices::GetClass(objRef); (sscli20 \ clr \ src \ vm \ comobject.cpp)中,如the answer所示:

IsPublic

我确认Write-Host ([System.Environment]::Version) ([Type]::GetType("System.__ComObject")).IsPublic 的行为取决于Framework版本。我在不同的VM中尝试了以下PowerShell脚本:

2.0.50727.3643 False (WinXP)
4.0.30319.18052 True (Win7)
4.0.30319.19079 True (Win8)

输出结果为:

False

显然,自.NET 2.0以来,它已从True更改为True。我同意__ComObjectinternal class __ComObject ...__ComObject)的声明不一致。我个人认为没有理由进行此类更改,因为获取{{1}}实例的唯一方法是通过互操作。