net - what can be done with reflection in c#
¿Por qué el tipo System.__ ComObject reclama(a veces) ser público cuando no lo es? (1)
Solo una rareza que descubrí cuando estaba reflexionando sobre todos los tipos para comprobar algo más por curiosidad.
¿Por qué la clase System.__ComObject
del ensamblado mscorlib.dll
(a veces?) System.__ComObject
ser pública cuando, de hecho, parece no ser pública? Si ejecuto el siguiente código en una aplicación de consola C # simple:
var t = Type.GetType("System.__ComObject");
Console.WriteLine(t.IsPublic); // "True" ?!
Console.WriteLine(t.IsVisible); // "False"
La salida parece conflictiva. Un tipo no anidado ( t.IsNested
es falso) debe dar el mismo valor de verdad para IsPublic
e IsPublic
. Cuando miro el montaje con IL DASM
veo:
.class private auto ansi beforefieldinit System.__ComObject
extends System.MarshalByRefObject
{
} // end of class System.__ComObject
que, para mí, se parece mucho a una clase no pública , algo que correspondería al código C # a continuación:
namespace System
{
// not public
internal class __ComObject : MarshalByRefObject
{
...
}
}
Cuando me comparo con otro tipo que tiene un nombre similar, System.__Canon
y modificadores de IL similares, tanto IsPublic
como IsPublic
devuelven false como se esperaba.
¿Alguien sabe por qué (y cuándo) Type.GetType("System.__ComObject").IsPublic
da verdad?
La implementación de Mono de __ComObject
puede dar algunas pistas. De hecho, se declara como interno , pero los comentarios dicen "No tiene métodos públicos, su funcionalidad se expone a través de System.Runtime.InteropServices.Marshal
" . No he buscado en Marshal
, pero asumo que es responsable de la implementación de GetType()
, por lo que también podría personalizar la propiedad de IsPublic
.
En mi experiencia, Type.GetType("System.__ComObject").IsPublic
siempre es true
. Con respecto a GetType("System.Net.Mail.MSAdminBase")
, creo que es una clase COM expuesta a través de un ensamblaje de interoperabilidad primario personalizado , donde la visibilidad de un tipo se puede controlar explícitamente (aunque es solo mi opinión, no se ha realizado ninguna investigación hecho).
[ACTUALIZAR]
IsPublic
el último código fuente de Framework y descubrí que estaba equivocado al suponer que la personalización de la propiedad __ComObject
para __ComObject
Type la realiza Marshal
. En realidad, se realiza mediante código no gestionado. Object.GetType()
se define dentro de Object.cs de esta manera:
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern Type GetType();
El código fuente no administrado para su implementación en .NET 4.x no está disponible, pero está available para .NET 2.0. Hay una excelente respuesta sobre la implementación de Object.GetType
en .NET 2.0. Acabo de agregar, IsPublic
se define por la interfaz System.Runtime.InteropServices._Type
que deriva System.Type
, y puede ser reemplazado por cualquiera de las clases System.Type
de System.Type
. Aparentemente, una implementación de dicha clase es devuelta por Object.GetType
, y eso sucede dentro de ObjectNative::GetClass
(sscli20 / clr / src / vm / comobject.cpp), como se muestra en la respuesta :
if (!objRef->IsThunking())
refType = typeHandle.GetManagedClassObject();
else
refType = CRemotingServices::GetClass(objRef);
Confirmo que el comportamiento de IsPublic
depende de la versión de Framework. Probé el siguiente script de PowerShell en diferentes máquinas virtuales:
Write-Host ([System.Environment]::Version) ([Type]::GetType("System.__ComObject")).IsPublic
La salida es:
2.0.50727.3643 False (WinXP)
4.0.30319.18052 True (Win7)
4.0.30319.19079 True (Win8)
Aparentemente, ha cambiado de False
a True
desde .NET 2.0. Estoy de acuerdo en que True
es inconsistente con la declaración de __ComObject
( internal class __ComObject ...
). Personalmente no veo ninguna razón para tal cambio, porque la única forma de obtener una instancia de __ComObject
es a través de la interoperabilidad.