2013-08-06 12 views
20

Dziwnie zdarzyło mi się odkryć, kiedy zastanawiałem się nad wszystkimi typami, aby sprawdzić coś innego z ciekawości.Dlaczego typ System .__ ComObject roszczenie (czasami) być publiczne, gdy nie jest?

Dlaczego klasa System.__ComObject z zespołu mscorlib.dll (czasami?) Twierdzi, że jest publiczna, gdy w rzeczywistości wydaje się być niepubliczna? Jeśli uruchomię następujący kod w prostej aplikacji konsoli C#:

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

wyjście wydaje się być w konflikcie. Typ niezgnieżdżony (t.IsNested jest fałszywy) powinien dawać tę samą wartość prawdy dla IsPublic i IsVisible. Kiedy patrzę na zespole z IL DASM widzę:

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

który dla mnie wygląda bardzo podobnie jak niepublicznej klasie, coś, co odpowiadałoby kodu C# poniżej:

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

Po porównaniu z innym typem, który ma podobną nazwę, System.__Canon i podobne modyfikatory IL, oba IsPublic i IsVisible zwrócą fałsz zgodnie z oczekiwaniami.

Czy ktoś wie, dlaczego (i kiedy) Type.GetType("System.__ComObject").IsPublic daje prawdziwe?

+1

System .__ ComObject i System .__ Canon są bardzo różne - pierwszy to obiekt COM (IsCOMObject == true) - dlatego uważam, że jest to Public, a drugi nie. –

+1

@Mihail Jeśli używam 'var t = typeof (Uri) .Assembly.GetType (" System.Net.Mail.MSAdminBase ");' Mam innego typu 't', który również' IsCOMObject', ale 'IsNotPublic'. Wydaje się to być "kontrprzykładem" do tego wyjaśnienia, chyba że jest to coś, co zależy od złożenia ('System.Net.Mail.MSAdminBase' jest w innym zestawie, w porównaniu do' System .__ ComObject'). –

+1

Wszystko, co mogę zrozumieć, to może być wada! Natknąłem się na podobne rzeczy, być może wy też się natknęliście. Kliknij [link] (http://microsoft.public.dotnet.framework.interop.narkive.com/06Y4MWuX/reflection-messing-up-the-type-hierarchy) – Nilesh

Odpowiedz

10

Mono's implementation z __ComObject może dać pewne wskazówki. Jest on rzeczywiście zadeklarowany jako wewnętrzny, ale komentarze mówią: "Nie ma żadnych publicznych metod, jego funkcjonalność jest ujawniona za pomocą System.Runtime.InteropServices.Marshal". Nie zagłębiłem się w Marshal, ale zakładam, że jest odpowiedzialny za implementację GetType(), więc może również dostosować właściwość IsPublic.

Z mojego doświadczenia wynika, że ​​Type.GetType("System.__ComObject").IsPublic zawsze jest true. Jeśli chodzi o GetType("System.Net.Mail.MSAdminBase"), to uważam, że jest to klasa COM wyeksponowana przez customized primary interop assembly, gdzie widoczność typu może być wyraźnie kontrolowana (chociaż to tylko moje myślenie, żadne badania nie zostały wykonane).

[UPDATE]

Mam latest Framework source code i okazało myliłem o moim założeniu, że dostosowanie IsPublic nieruchomości na __ComObject typu odbywa się poprzez Marshal. W rzeczywistości odbywa się to za pomocą niezarządzanego kodu. Object.GetType() jest zdefiniowana wewnątrz Object.cs tak:

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

Kod źródłowy niekontrolowana dla jego realizacji w .NET 4.x nie jest dostępny, ale jest available dla .NET 2.0. Istnieje implementacja excellent answer o Object.GetType w .NET 2.0. Dodałbym, że IsPublic jest zdefiniowany przez interfejs System.Runtime.InteropServices._Type, z którego pochodzi System.Type i może być nadpisany przez dowolne z System.Type -klimatycznych klas. Najwyraźniej implementacja takiej klasy jest zwracana przez Object.GetType, a dzieje się to wewnątrz ObjectNative::GetClass (sscli20 \ clr \ src \ vm \ comobject.CPP), jak pokazano w the answer:

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

Potwierdzam, że zachowanie IsPublic zależy od wersji ramowej. Próbowałem następujący skrypt PowerShell w różnych maszyn wirtualnych:

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

wyjście jest:

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

Widocznie to się zmieniło od False do True od .NET 2.0. Zgadzam się, że True jest niezgodne z deklaracją __ComObject (internal class __ComObject ...). Osobiście nie widzę powodu dla takiej zmiany, ponieważ jedynym sposobem uzyskania instancji __ComObject jest interop.

+0

Nie testowałem tego w Mono. Nie znalazłem nic w łączonym kodzie źródłowym, które wydawało mi się istotne. Nie jestem pewien, co masz na myśli mówiąc o 'GetType' i' IsPublic'. Ta ostatnia jest nie-wirtualną (choć implementującą interfejs) właściwość instancji w abstrakcyjnej klasie 'System.Type', więc potrzebuję wyjaśnienia, w jaki sposób' __ComObject' lub 'Marshal' może spersonalizować" to "(twoje słowa). Powodem, dla którego mówię "(czasami)" w pytaniu, jest to, że przetestowałem to w PowerShell na dwóch różnych maszynach, z tym że jeden komputer traktuje (przez PowerShell) '__ComObject' jako niepubliczny, najwyraźniej. –

+1

Próbowałem następujące rzeczy z PowerShell: 'Write-Host ([System.Environment] :: Version) ([Type] :: GetType (" System .__ ComObject ")). IsPublic', wynik:' 4.0.30319.19079 True' (Win8), '4.0.30319.18052 True' (Win7),' 2.0.50727.3643 False' (WinXP). Wygląda na to, że wynik 'IsPublic' dla' __ComObject' zależy od wersji framework. Zrobię trochę badań i przedstawię wyjaśnienie "Marszałka", o które prosiłeś. – Noseratio

+0

Przykro mi, nie jestem pewien, co masz na myśli mówiąc, że ('IsPublic') _jest nie-wirtualną (choć implementującą interfejs) właściwość instance_ na abstrakcyjnym' System.Type'. Właściwość jest zdefiniowana w interfejsie 'System.Runtime.InteropServices._Type', więc jest wirtualna z definicji i może zostać nadpisana przez dowolną klasę pochodną, ​​taką samą jak' IsCOMObject'. 'System.Type' nie implementuje' IsPublic', ale niektóre z jego klas pochodnych, np. 'System.RuntimeType'. Przyznaję, że nie miałem racji, zakładając, że personalizacja jest wykonywana przez 'Marshala' choć faktycznie jest to robione niezarządzanym kodem. Zaktualizowałem swoją odpowiedź, podając więcej szczegółów. – Noseratio