2013-08-06 12 views
20

Solo una stranezza mi è capitato di scoprire quando stavo riflettendo su tutti i tipi per controllare qualcos'altro per curiosità.Perché il tipo System .__ ComObject dichiara (a volte) di essere pubblico quando non lo è?

Perché la classe dell'assembly mscorlib.dll (a volte?) Dichiara di essere pubblica quando in realtà sembra non essere pubblica? Se eseguo il codice seguente in una semplice applicazione console C#:

var t = Type.GetType("System.__ComObject"); 
Console.WriteLine(t.IsPublic); // "True" ?! 
Console.WriteLine(t.IsVisible); // "False" 

l'output sembra in conflitto. Un tipo non annidato (t.IsNested è falso) dovrebbe fornire lo stesso valore di verità per IsPublic e IsVisible. Quando guardo il montaggio con IL DASM vedo:

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

che, a me, sembra molto simile a un classe non-pubblico , qualcosa che corrisponderebbe al C# codice qui sotto:

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

Quando eseguo il confronto con un altro tipo che ha un nome simile, System.__Canon, e modificatori IL simili, sia IsPublic sia IsVisible restituiscono false come previsto.

Qualcuno sa perché (e quando) Type.GetType("System.__ComObject").IsPublic dà vero?

+1

System .__ ComObject e System .__ Canon sono molto diversi: prima è un oggetto COM (IsCOMObject == true) - è per questo che penso che sia Pubblico e il secondo no. –

+1

@Mihail Se uso 'var t = typeof (Uri) .Assembly.GetType (" System.Net.Mail.MSAdminBase ");' Ho un altro tipo 't' che anche' IsCOMObject', ma 'IsNotPublic'. Questo sembra essere un "controesempio" a questa spiegazione, a meno che non si tratti di qualcosa che dipende dall'assemblaggio ('System.Net.Mail.MSAdminBase' si trova in un altro assembly, rispetto a' System .__ ComObject'). –

+1

Tutto quello che riesco a capire è che potrebbe essere un difetto! Mi sono imbattuto in qualcosa di simile, forse anche voi vi siete imbattuti nello stesso modo. Segui [collegamento] (http://microsoft.public.dotnet.framework.interop.narkive.com/06Y4MWuX/reflection-messing-up-the-type-hierarchy) – Nilesh

risposta

10

Mono's implementation di __ComObject può dare alcuni indizi. È infatti dichiarato come interno, ma i commenti dicono "Non ha metodi pubblici, la sua funzionalità è esposta tramite System.Runtime.InteropServices.Marshal". Non ho scavato in Marshal, ma suppongo che sia responsabile per l'implementazione di GetType(), quindi potrebbe personalizzare anche la proprietà IsPublic.

Nella mia esperienza, Type.GetType("System.__ComObject").IsPublic è sempre true. Per quanto riguarda GetType("System.Net.Mail.MSAdminBase"), credo che sia una classe COM esposta tramite un customized primary interop assembly, in cui la visibilità di un tipo può essere esplicitamente controllata (anche se è solo un mio pensiero, nessuna ricerca è stata fatta).

[UPDATE]

Ho il latest Framework source code e ha trovato mi sbagliavo circa la mia ipotesi che la personalizzazione dei IsPublic immobili per __ComObject tipo è fatto da Marshal. In realtà, è fatto da codice non gestito. Object.GetType() definita all'interno di Object.cs come questo:

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

Il codice sorgente non gestito per la sua attuazione in 4.x .NET non è disponibile, ma è available for .NET 2.0. C'è un'implementazione excellent answer sull'implementazione Object.GetType in .NET 2.0. Devo solo aggiungere, IsPublic è definito dall'interfaccia System.Runtime.InteropServices._Type che deriva da System.Type e può essere sovrascritto da una qualsiasi delle classi dipendenti da System.Type. Apparentemente, un'implementazione di tale classe viene restituita da Object.GetType e ciò avviene all'interno di ObjectNative::GetClass (sscli20 \ clr \ src \ vm \ comobject.cpp), come mostrato nella the answer:

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

Confermo che il comportamento di IsPublic dipende dalla versione Framework. Ho provato il seguente script PowerShell in diverse macchine virtuali:

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

L'output è:

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

A quanto pare, ha cambiato False-True dal .NET 2.0. Sono d'accordo che True non è coerente con la dichiarazione di __ComObject (internal class __ComObject ...). Personalmente non vedo alcun motivo per questo cambiamento, perché l'unico modo per ottenere un'istanza di __ComObject è attraverso l'interoperabilità.

+0

Non l'ho provato in Mono. Non ho trovato nulla nel codice sorgente che hai collegato che mi sembrava pertinente. Non sono sicuro di cosa intendi dire su "GetType" e "IsPublic". Quest'ultima è una proprietà di istanza non virtuale (sebbene di interfacciamento all'implementazione) nella classe astratta 'System.Type', quindi ho bisogno di una spiegazione su come" __ComObject' o 'Marshal'" potrebbe personalizzare "esso (le tue parole). La ragione per cui dico "(qualche volta)" nella domanda, è che ho provato questo in PowerShell su due macchine diverse, con una macchina che tratta (tramite PowerShell) '__ComObject' come non pubblica, apparentemente. –

+1

Ho provato quanto segue con PowerShell: 'Write-Host ([System.Environment] :: Version) ([Type]: GetType (" System .__ ComObject ").) IsPublic', l'output:' 4.0.30319.19079 True' (Win8), '4.0.30319.18052 True' (Win7),' 2.0.50727.3643 False' (WinXP). Apparentemente, il risultato di 'IsPublic' per' __ComObject' dipende dalla versione del framework. Farò qualche ricerca e fornirò la spiegazione su "Marshal" che hai richiesto. – Noseratio

+0

Mi spiace, non sono sicuro di cosa intendi dicendo che ('IsPublic') _ è una proprietà di istanza non virtuale (sebbene di interfacciamento all'implementazione) sull'astratto' System.Type'. La proprietà è definita nell'interfaccia 'System.Runtime.InteropServices._Type', quindi è virtuale per definizione e può essere sovrascritta da qualsiasi classe derivata, come' IsCOMObject'. 'System.Type' non implementa' IsPublic', ma alcune delle sue classi derivate, ad es. 'System.RuntimeType'. Ammetto di aver sbagliato supponendo che la personalizzazione sia fatta da "Marshal", ma in realtà è fatto con codice non gestito. Ho aggiornato la mia risposta con maggiori dettagli. – Noseratio

Problemi correlati