为什么键入System__ComObject声明(有时)是公共的,而不是

本文关键字:有时 System ComObject 声明 为什么 | 更新日期: 2023-09-27 18:26:48

当我出于好奇对所有类型进行反思以检查其他内容时,我偶然发现了一个奇怪的事情。

为什么程序集mscorlib.dll的类System.__ComObject(有时?)声称是公共的,而实际上它似乎是非公共的?如果我在一个简单的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为什么(以及何时)成立吗?

为什么键入System__ComObject声明(有时)是公共的,而不是

Mono对__ComObject的实现可能会提供一些线索。它确实被声明为内部,但评论说"它没有公共方法,它的功能是通过System.Runtime.InteropServices.Marshal暴露的"。我还没有深入研究Marshal,但我认为它负责GetType()的实现,所以它也可以自定义IsPublic属性。

根据我的经验,Type.GetType("System.__ComObject").IsPublic永远是true。关于GetType("System.Net.Mail.MSAdminBase"),我认为它是一个通过自定义的主互操作程序集公开的COM类,在其中可以显式控制类型的可见性(尽管这只是我的想法,但还没有进行任何研究)。

[更新]

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

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

其在.NET 4.x中实现的非托管源代码不可用,但可用于.NET 2.0。关于Object.GetType在.NET 2.0中的实现,有一个很好的答案。我只想补充一点,IsPublic是由System.Type派生的System.Runtime.InteropServices._Type接口定义的,并且可以被任何System.Type派生类覆盖。显然,这样的类的实现是由Object.GetType返回的,这发生在ObjectNative::GetClass(sscli20''clr''src''vm''cobject.cpp)内部,如答案所示:

if (!objRef->IsThunking())
    refType = typeHandle.GetManagedClassObject();
else
    refType = CRemotingServices::GetClass(objRef);

我确认IsPublic的行为取决于框架版本。我在不同的虚拟机中尝试了以下PowerShell脚本:

Write-Host ([System.Environment]::Version) ([Type]::GetType("System.__ComObject")).IsPublic

输出为:

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

显然,从.NET 2.0开始,它已经从False变成了True。我同意True__ComObjectinternal class __ComObject ...)的声明不一致。我个人认为没有理由进行这样的更改,因为获得__ComObject实例的唯一方法是通过interop。