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

Jep*_*sen 20 .net c# reflection encapsulation cil

只是奇怪的是,当我反思所有类型时,我偶然发现了好奇心来检查其他东西.

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

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

输出似乎有冲突.非嵌套类型(t.IsNested为false)应为IsPublic和提供相同的真值IsVisible.当我看到装配时,IL DASM我看到:

.class private auto ansi beforefieldinit System.__ComObject
       extends System.MarshalByRefObject
{
} // end of class System.__ComObject
Run Code Online (Sandbox Code Playgroud)

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

namespace System
{
    // not public
    internal class __ComObject : MarshalByRefObject
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

当我比较其他类型的具有类似的名称,System.__Canon以及类似IL改性剂,既IsPublicIsVisible预期返回false.

有谁知道为什么(和什么时候)Type.GetType("System.__ComObject").IsPublic给出了真实的?

nos*_*tio 10

Mono的实现__ComObject可能提供一些线索.它确实被宣布为内部,但评论说"它没有公开的方法,它的功能暴露在低谷System.Runtime.InteropServices.Marshal".我没有挖Marshal,但我认为它负责实施GetType(),所以它也可以定制IsPublic属性.

根据我的经验,Type.GetType("System.__ComObject").IsPublic总是如此true.关于GetType("System.Net.Mail.MSAdminBase"),我相信它是通过定制的主互操作程序集暴露的COM类,其中可以明确控制类型的可见性(虽然这只是我的想法,没有进行过研究).

[UPDATE]

我有最新的Framework源代码,发现我错误地假设我IsPublic__ComObject类型的属性定制是由Marshal.实际上,它是由非托管代码完成的.Object.GetType()在Object.cs中定义如下:

[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern Type GetType(); 
Run Code Online (Sandbox Code Playgroud)

在.NET 4.x中实现它的非托管源代码不可用,但它用于.NET 2.0.关于.NET 2.0中的实现,有一个很好的答案Object.GetType.我只是添加,IsPublic是由派生定义的System.Runtime.InteropServices._Type接口定义的System.Type,并且可以被任何System.Type-descendent类覆盖.显然,这样的类的实现是通过返回Object.GetType,这是怎么回事内ObjectNative::GetClass(sscli20\CLR\SRC \虚拟机\ comobject.cpp),如图答案:

if (!objRef->IsThunking())
    refType = typeHandle.GetManagedClassObject();
else
    refType = CRemotingServices::GetClass(objRef);
Run Code Online (Sandbox Code Playgroud)

我确认行为IsPublic取决于Framework版本.我在不同的VM中尝试了以下PowerShell脚本:

Write-Host ([System.Environment]::Version) ([Type]::GetType("System.__ComObject")).IsPublic
Run Code Online (Sandbox Code Playgroud)

输出是:

2.0.50727.3643 False (WinXP)
4.0.30319.18052 True (Win7)
4.0.30319.19079 True (Win8)
Run Code Online (Sandbox Code Playgroud)

显然,它已经从FalseTrue自.NET 2.0.我同意这True__ComObject(internal class __ComObject ...)的声明不一致.我个人认为没有理由进行这样的改变,因为获得实例的唯一方法__ComObject是通过互操作.