2012-10-10 15 views
10

Po wyświetleniu wszystkich typów w bieżącym AppDomain widzę moje typy ogólne z ogólnymi symbolami zastępczymi. Jednakże, jeśli utworzę moje typy ogólne z typem, a następnie listę wszystkich typów w appDomain, nie widzę nowo utworzonych typów zamkniętych.Lista typów zamkniętych utworzonych przez środowisko wykonawcze z otwartych typów ogólnych

W poniższym przykładzie, wyjście jest tylko:

Foo`1[T] 

szukam typu zamkniętego:

Foo`1[System.Int32] 

Czy istnieje sposób, aby zobaczyć zamkniętych typów że Runtime stworzony dla mnie w oparciu o moje otwarte rodzaje generyczne?

class Foo<T> 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var tmp = new Foo<int>(); 
     ListTypes(); 
    } 

    private static void ListTypes() 
    { 
     var types = from assembly in AppDomain.CurrentDomain.GetAssemblies() 
         from type in assembly.GetTypes() 
         where type.Name.Contains("Foo") 
         select type; 

     foreach (var type in types) 
      Console.WriteLine(type.ToString()); 
    } 
} 

Próbowałem również znaleźć wszystkie typy za pomocą ogólnego argumentu w nadziei na odkrycie zamkniętego typu.

class Foo<T> 
{ 
} 

class Bar 
{ 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var tmp = new Foo<Bar>(); 
     ListTypes(); 
    } 

    private static void ListTypes() 
    { 
     var types = from assembly in AppDomain.CurrentDomain.GetAssemblies() 
         from type in assembly.GetTypes() 
         where type.IsGenericType 
         && type.GetGenericArguments().Contains(typeof(Bar)) 
         select type; 

     foreach (var type in types) 
      Console.WriteLine(type.ToString()); 
    } 
} 

To tylko po to, by zaspokoić moją ciekawość.

+0

Jeśli dobrze rozumiem, ta refleksja po prostu otrzyma typy zdefiniowane w metadanych, które zawierają w tekście tylko rodzaj definicji rodzajowej. Ponieważ konkretne typy mogą być konstruowane z typów generycznych dynamicznie w czasie wykonywania (ponownie za pomocą refleksji, przekazując ogólne argumenty) - widać, że nie ma sposobu na umieszczenie ich w metadanych ... tak, jakiś inny mechanizm (nie eksploracja metadanych) musiałaby zostać wykorzystana do znalezienia określonych typów, które zostały utworzone. –

+0

Rozumiem. To wyjaśnia, dlaczego nie widzę typów utworzonych w środowisku wykonawczym, nie ma ich w metadanych, które są przedmiotem refleksji. Zastanawiam się, jaki byłby ten inny mechanizm? –

+1

Istnieje prywatny typ wewnątrz mscorlib o nazwie TypeNameParser, który ma metodę GetNames zwracającą tablicę ciągów znaków, ale gdy próbuję użyć jej w ramach refleksji, otrzymuję fatalne błędy przypominające mi, jak mało wiem o obiektach COM i współdziałaniu, i że generalnie nie powinienem mieszać się z prywatnymi typami wewnątrz mscorlib :-P Nadal jednak szukam eleganckiego rozwiązania. –

Odpowiedz

5

ile można zrozumieć, w tym przypadku Foo<T> jest otwarty niezwiązanego typ ogólny, aby w czasie pracy CLR wykorzysta je jako projekt/szkieletu konstruować i zamknięcia typu rodzajowego z rodzajem parametru typ danych (Foo<int> , Foo<object> itd.). Zasadniczo Foo<int> jest konstrukcją wykonawczą zbudowaną z szkieletu Foo<T>.

Teraz, w czasie wykonywania można uzyskać typ Foo<int> albo za pomocą typeof(Foo<int>) lub typeof(Foo<>).MakeGenericType(new[] { typeof(int) }) a to nie to samo Type i to nie ma sensu, aby była ona. Ale przyjrzyj się bliżej, a zobaczysz, że zarówno jak i typeof(Foo<int>) udostępniają ten sam token metadanych i GUID.

Inną interesującą rzeczą jest to, że typeof(Foo<int>).Assembly będzie tym, czego można się spodziewać, ale jak już zauważyliście, nie można tego typu uzyskać od Zgromadzenia.

To dlatego, że Foo<int> nie jest zdefiniowany w złożeniu (można sprawdzić metadane zespołu za pomocą Reflector/ILSpy). W czasie wykonywania CLR utworzy ("konstruuje") wyspecjalizowaną ("zamkniętą") wersję Foo<T> dla Foo<int> (tak skonstruowaną zamkniętą definicję nieograniczonej otwartej definicji typu ogólnego) i "da" ją Type. Więc jeśli CLR nie ujawnia w jakiś sposób listy zamkniętych rodzajów generycznych, które generuje w czasie wykonywania, nie masz szczęścia.

Również tutaj jest to fragment, który może potwierdzić to, co mówię:

Choć każda budowa typu rodzajowego, takie jak węzeł < form> i Węzeł < string>, ma swój własny odrębny typ tożsamość, CLR jest w stanie ponownie wykorzystać znaczną część kodu skompilowanego przez JIT między instancjami typu . To drastycznie zmniejsza nadpisywanie kodu i jest możliwe , ponieważ różne wystąpienia typu ogólnego są rozszerzane w czasie wykonywania . Wszystko, co istnieje skonstruowanego typu w czasie kompilacji, jest typem odniesienia typu . Gdy zespoły A i B odnoszą się do generycznego typu zdefiniowanego w trzecim zespole, ich konstruowane typy są rozszerzane w czasie wykonywania .Oznacza to, że oprócz udostępniania identyfikatorów typu CLR (w stosownych przypadkach), tworzenie instancji z zestawów A i B również udostępnia zasoby czasu pracy, takie jak kod natywny i rozszerzone metadane.

http://msdn.microsoft.com/en-us/magazine/cc163683.aspx

+2

To jest trochę ciężkiej "magii CLR czasu pracy": konstruktor statyczny Foo jest wywoływany dla każdego zamkniętego typu "ładowanie" :-) P.S. Gdzie jest Skeet, kiedy go potrzebujesz? –

1

odpowiedź Iwana jest przeważnie rację, ale twierdzi, że metadane montażu nie zawiera żadnych informacji o budowanych typów nie jest całkiem poprawne. Wszystkie konstruowane typy są zdefiniowane w zestawie, który je wykorzystuje i narzędzia takie jak Mono.Cecil pozwalają to zobaczyć. Zbudowane typy nie są odsłonięte przez odbicie, a nawet Mono.Cecil sprawia, że ​​trudno je zlokalizować.

Zasadniczo musisz przejść przez wszystkie typy, które są użyte w zespole w postaci, np. typy właściwości, typy zwracane, typy zmiennych lokalnych itd. Informacje te są zawarte w metadanych zestawu i można je względnie łatwo wyliczyć za pomocą Mono.Cecil. Następnie zastosuj prosty filtr, który wykrywa, czy typ został skonstruowany. Zauważ, że być może będziesz musiał przejść przez kilka złożeń, które odwołują się do ogólnej definicji typu, aby znaleźć wszystkie typy z niego zbudowane.

Istnieją dwa ograniczenia tego rozwiązania. Po pierwsze, typy skonstruowane poprzez odbicie naturalnie nie pojawiają się w żadnym zespole. Po drugie, niektóre konstruowane typy są osadzone w typach ogólnych/metodach, a ich argumenty typu generycznego są znane dopiero po utworzeniu ich rodzica/metody z konkretnymi argumentami typu ogólnego.

Powiązane problemy