当我反思所有类型时,碰巧发现了一些奇怪的事情,以便出于好奇而检查其他内容。
为什么大会System.__ComObject
的班级mscorlib.dll
(有时?)声称是公开的,而事实上它似乎是非公开的?如果我在一个简单的C#控制台应用程序中运行以下代码:
var t = Type.GetType("System.__ComObject");
Console.WriteLine(t.IsPublic); // "True" ?!
Console.WriteLine(t.IsVisible); // "False"
输出似乎有冲突。非嵌套类型(t.IsNested
为false)应为IsPublic
和IsVisible
提供相同的真值。当我用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修饰符的其他类型进行比较时,IsPublic
和IsVisible
都会按预期返回false。
有谁知道为什么(以及何时)Type.GetType("System.__ComObject").IsPublic
给出了真的?
答案 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
的实现。我只是添加,IsPublic
由System.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
。我同意__ComObject
与internal class __ComObject ...
(__ComObject
)的声明不一致。我个人认为没有理由进行此类更改,因为获取{{1}}实例的唯一方法是通过互操作。