2013-08-06 13 views
20

Nur eine Kuriosität, die ich entdeckte, als ich über alle Typen nachdachte, um etwas anderes aus Neugier zu überprüfen.Warum behauptet der Typ System .__ ComObject (manchmal), öffentlich zu sein, wenn es nicht ist?

Warum behauptet die Klasse System.__ComObject der Baugruppe mscorlib.dll (manchmal?), Öffentlich zu sein, obwohl sie in der Tat nicht öffentlich zu sein scheint? Wenn ich den folgenden Code in einer einfachen C# -Konsolenanwendung ausführen:

scheint die Ausgabe widersprüchlich. Ein nicht verschachtelter Typ (t.IsNested ist falsch) sollte den gleichen Wahrheitswert für IsPublic und IsVisible ergeben. Als ich bei der Montage mit IL DASM sehe ich sehen:

.class private auto ansi beforefieldinit System.__ComObject 
     extends System.MarshalByRefObject 
{ 
} // end of class System.__ComObject 

was, mir, sieht sehr ähnlich wie eine nicht-öffentliche Klasse, etwas, das mit dem C# -Code entsprechen würde unter:

namespace System 
{ 
    // not public 
    internal class __ComObject : MarshalByRefObject 
    { 
     ... 
    } 
} 

Wenn ich mit einem anderen Typ mit ähnlichem Namen, System.__Canon, und ähnlichen IL-Modifikatoren vergleiche, geben sowohl IsPublic als auch IsVisible false wie erwartet zurück.

Weiß jemand, warum (und wann) Type.GetType("System.__ComObject").IsPublic gibt wahr?

+1

System .__ ComObject und System .__ Canon sind sehr unterschiedlich - zuerst ist COM-Objekt (IsCOMObject == true) - das ist, warum ich denke, es ist öffentlich und die zweite nicht. –

+1

@Mihail Wenn ich 'var t = typeof (Uri) .Assembly.GetType (" System.Net.Mail.MSAdminBase ") verwende;' Ich habe einen anderen Typ 't', der auch' IsCOMObject', aber 'IsNotPublic' ist. Dies scheint also ein "Gegenbeispiel" zu dieser Erklärung zu sein, es sei denn, dies ist etwas, das von der Assembly abhängt ("System.Net.Mail.MSAdminBase" befindet sich in einer anderen Assembly, verglichen mit "System .__ ComObject"). –

+1

Alles was ich herausfinden kann ist, das könnte ein Defekt sein! Ich bin auf ähnliche Dinge gestoßen, vielleicht seid ihr auch auf dasselbe gestoßen. Folgen Sie [link] (http://microsoft.public.dotnet.framework.interop.narkive.com/06Y4MWuX/reflection-messing-up-the-type-hierarchy) – Nilesh

Antwort

10

Mono's implementation von __ComObject kann einige Hinweise geben. Es ist in der Tat als interne deklariert, aber die Kommentare sagen "Es hat keine öffentlichen Methoden, seine Funktionalität ist durch System.Runtime.InteropServices.Marshal" ausgesetzt. Ich habe nicht in Marshal gegraben, aber ich würde annehmen, dass es für die Implementierung von GetType() verantwortlich ist, also könnte es IsPublic Eigenschaft auch besonders anfertigen.

Meiner Erfahrung nach ist Type.GetType("System.__ComObject").IsPublic immer true. In Bezug auf GetType("System.Net.Mail.MSAdminBase"), ich glaube, es ist eine COM-Klasse über eine customized primary interop assembly ausgesetzt, wo die Sichtbarkeit eines Typs explizit gesteuert werden kann (obwohl es nur mein Denken ist, wurde keine Forschung durchgeführt).

[UPDATE]

Ich habe die latest Framework source code bekam und fand ich über meine Annahme falsch war, dass die Anpassung von IsPublic Immobilien für __ComObject Typ von Marshal erfolgt. Tatsächlich wird es durch nicht verwalteten Code gemacht. Object.GetType() innerhalb Object.cs wie folgt definiert:

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

Der unmanaged Quellcode für seine Implementierung in .NET 4.x nicht verfügbar ist, aber es ist available für .NET 2.0. Es gibt eine excellent answer über Object.GetType Implementierung in .NET 2.0. Ich würde nur hinzufügen, IsPublic wird durch System.Runtime.InteropServices._Type Schnittstelle definiert, die System.Type abgeleitet ist, und kann von System.Type -descendent Klassen überschrieben werden. Anscheinend wird eine Implementierung einer solchen Klasse von Object.GetType zurückgegeben, und das passiert innerhalb von ObjectNative::GetClass (sscli20 \ clr \ src \ vm \ comobject.CPP), wie gezeigt in the answer:

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

Ich bestätige, dass das Verhalten von IsPublic auf der Framework-Version abhängig ist. Ich habe versucht, den folgenden Powershell-Skript in verschiedenen VMs:

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

Die Ausgabe lautet:

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

Anscheinend es False-True seit .NET 2.0 geändert hat. Ich stimme zu, dass True nicht mit der Deklaration von __ComObject (internal class __ComObject ...) übereinstimmt. Ich persönlich sehe keinen Grund für eine solche Änderung, weil die einzige Möglichkeit, eine Instanz von __ComObject zu erhalten, über Interop ist.

+0

Ich habe dies nicht in Mono getestet. Ich habe nichts in dem Quellcode gefunden, den Sie verlinkt haben, der mir relevant erschien. Ich bin mir nicht sicher, was Sie über 'GetType' und' IsPublic' sagen wollen. Letzteres ist eine nichtvirtuelle (wenn auch Schnittstellen implementierende) Instanzeigenschaft in der abstrakten 'System.Type' Klasse, daher brauche ich eine Erklärung dafür, wie' __ComObject' oder 'Marshal'" es (Ihre Wörter) anpassen könnte. Der Grund, warum ich "(manchmal)" in der Frage sage, ist, dass ich dies in PowerShell auf zwei verschiedenen Rechnern getestet habe, wobei ein Rechner (über PowerShell) anscheinend "__ComObject" als nicht-öffentlich behandelt hat. –

+1

Ich habe mit PowerShell Folgendes versucht: 'Write-Host ([System.Environment] :: Version) ([Type] :: GetType (" System .__ ComObject ")). IsPublic', die Ausgabe:' 4.0.30319.19079 True' (Win8), '4.0.30319.18052 True' (Win7),' 2.0.50727.3643 False' (WinXP). Offensichtlich hängt das Ergebnis von 'IsPublic' für '__ComObject' von der Framework-Version ab. Ich werde etwas recherchieren und die Erklärung zu "Marshal" liefern, die du angefordert hast. – Noseratio

+0

Sorry, ich bin mir nicht sicher, was Sie meinen, indem Sie sagen, dass ('IsPublic') _ eine nichtvirtuelle (obwohl Schnittstelle implementierende) Instanzeigenschaft_ auf dem abstrakten' System.Type' ist. Die Eigenschaft ist in der 'System.Runtime.InteropServices._Type'-Schnittstelle definiert, daher ist sie per Definition virtuell und kann von jeder abgeleiteten Klasse wie' IsCOMObject' überschrieben werden. "System.Type" implementiert "IsPublic" nicht, aber einige seiner abgeleiteten Klassen tun dies, z. 'System.RuntimeType'. Ich gebe zu, dass ich falsch lag, wenn man annimmt, dass die Anpassung von 'Marshal' vorgenommen wird, obwohl es tatsächlich mit nicht verwaltetem Code gemacht wird. Ich habe meine Antwort mit weiteren Details aktualisiert. – Noseratio

Verwandte Themen