Just an oddity I happened to discover when I was reflecting over all types to check something else out of curiosity.
Why does the class System.__ComObject
of the assembly mscorlib.dll
(sometimes?) claim to be public when in fact it seems to be non-public? If I run the following code in a simple C# console application:
var t = Type.GetType("System.__ComObject");
Console.WriteLine(t.IsPublic); // "True" ?!
Console.WriteLine(t.IsVisible); // "False"
the output seems conflicting. A non-nested type (t.IsNested
is false) should give the same truth value for IsPublic
and IsVisible
. When I look at the assembly with IL DASM
I see:
.class private auto ansi beforefieldinit System.__ComObject
extends System.MarshalByRefObject
{
} // end of class System.__ComObject
which, to me, looks very much like a non-public class, something which would correspond to the C# code below:
namespace System
{
// not public
internal class __ComObject : MarshalByRefObject
{
...
}
}
When I compare to another type which has a similar name, System.__Canon
, and similar IL modifiers, both IsPublic
and IsVisible
return false as expected.
Does anyone know why (and when) Type.GetType("System.__ComObject").IsPublic
gives true?
Mono's implementation of __ComObject
may give some clues. It is indeed declared as internal, but the comments say "It has no public methods, its functionality is exposed trough System.Runtime.InteropServices.Marshal
". I haven't dug into Marshal
, but I would assume it is responsible for the implementation of GetType()
, so it could customize IsPublic
property too.
In my experience, Type.GetType("System.__ComObject").IsPublic
is always true
. Regarding GetType("System.Net.Mail.MSAdminBase")
, I believe it is a COM class exposed via a customized primary interop assembly, where the visibility of a type can be explicitly controlled (although it's just my thinking, no research has been done).
[UPDATE]
I've got the latest Framework source code and found I was wrong about my assumption that customization of IsPublic
property for __ComObject
Type is done by Marshal
. Actually, it is done by unmanaged code. Object.GetType()
is defined inside Object.cs like this:
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern Type GetType();
The unmanaged source code for its implementation in .NET 4.x is not available, but it is available for .NET 2.0. There's an excellent answer about Object.GetType
implementation in .NET 2.0. I'd just add, IsPublic
is defined by System.Runtime.InteropServices._Type
interface which System.Type
derives from, and can be overridden by any of System.Type
-descendent classes. Apparently, an implementation of such class is returned by Object.GetType
, and that's happening inside ObjectNative::GetClass
(sscli20\clr\src\vm\comobject.cpp), as shown in the answer:
if (!objRef->IsThunking())
refType = typeHandle.GetManagedClassObject();
else
refType = CRemotingServices::GetClass(objRef);
I confirm that the behavior of IsPublic
depends on the Framework version. I tried the following PowerShell script in different VMs:
Write-Host ([System.Environment]::Version) ([Type]::GetType("System.__ComObject")).IsPublic
The output is:
2.0.50727.3643 False (WinXP)
4.0.30319.18052 True (Win7)
4.0.30319.19079 True (Win8)
Apparently, it has changed from False
to True
since .NET 2.0. I agree that True
is inconsistent with the declaration of __ComObject
(internal class __ComObject ...
). I personally see no reason for such change, because the only way to get an instance of __ComObject
is through interop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With