2011-07-15 15 views
7

Gdy mamy coś takiego:Jak stworzyć skonstruowaną typu rodzajowego bez podania jakiegokolwiek rodzaju parametry

interface ISomething<U,V> { ... } 
class Something<U,V> : ISomething<U,V> { ... } 

typeof(ISomething<,>) i typeof(Something<,>) spowoduje „ogólnych definicji typu”. Ale jeśli mamy do rodzaju interfejsu jako interfejs realizowanego przez klasę, będzie to rodzaj skonstruowane, że żaden z jego parametrów typu są faktycznie związane:

typeof(Something<,>).GetInterfaces().SingleOrDefault() 

MSDN specjalnie wspomina o tym. To, czego chcę, to skonstruowanie tego samego typu (typu skonstruowanego) o wartości ISomething<,> bezpośrednio (bez podklasy i szukających typu bazowego) i nie mogłem znaleźć żadnego sposobu, aby to zrobić.

Dodatkowe informacje:

Próbowałem nawet to:

Type t1 = typeof(ISomething<,>); 
Type t2 = t1.MakeGenericType(t1.GetGenericArguments()) // Yields a generic type definition 

Type t3 = typeof(Something<,>).GetInterfaces().SingleOrDefault(); 

W powyższym kodzie:

t1.Equals(t2) to prawda, ale t1.Equals(t3) jest fałszywa, ponieważ t3 oczywiście jest zbudowany.

Co zaskakujące, t1.GetGenericArguments()[0].Equals(t3.GetGenericArguments()[0]) jest fałszywe, chociaż oba są otwarte (IsGenericParameter = true) i nie mogłem znaleźć żadnej różnicy w ich właściwościach.

Oto, dlaczego muszę to zrobić: Potrzebuję kanonicznej formy przechowywania obiektów typu na liście. Obiekty czasami pochodzą z klas bazowych/interfejsów (takich jak t3 powyżej), a czasami bezpośrednio (takich jak t1). Będę musiał móc porównać je ze sobą. Nie mogę zapisać ogólnej definicji typu (używając .GetGenericTypeDefinition()), ponieważ czasami będę miał częściowo otwarty zbudowany rodzaj ogólny (jak ISomething), a GetGenericTypeDefinition da mi typ bez określonych argumentów typu.

Jedynym sposobem na stworzenie kanonicznych typów, o których myślę, że może działać, jest sprawdzenie, czy wszystkie argumenty typu są niezwiązane i wykonanie GetGenericTypeDefinition. W przeciwnym razie zachowaj skonstruowany typ.

+0

I nie sądzę, że to działa: „sprawdź, czy wszystkie argumenty typu są niezwiązane i wykonaj GetGenericTypeDefinition, w przeciwnym razie zachowaj skonstruowany typ. " Załóżmy, że masz typ "I ". Wszystkie argumenty typu są niezwiązanymi parametrami typu, ale jest to inny typ niż 'I '. –

+2

Odp: "Zaskakująco ..." - to wcale nie jest zaskakujące. Podejrzewam, że częścią tego zamieszania jest to, że masz dwa zupełnie różne typy o nazwie "U" i dwa zupełnie różne typy o nazwie "V". Oczywiście 'I <,>' różni się od 'I ' na zaimplementowanej liście interfejsu; pierwsza jest sparametryzowana za pomocą '' zadeklarowanej przez 'I', a druga jest sparametryzowana za pomocą' 'zadeklarowanej przez' Something'. Tylko dlatego, że parametry typu mają takie same nazwy, nie są tego samego typu. –

+0

Jeśli mam skonstruowane 'I ' i wywołanie na GetGenericTypeDefinition() na nim, da mi 'typeof (I )'? – Iravanchi

Odpowiedz

4

Dostajesz tutaj wszystko, co się zepsuło. Sprawdź wyniki tego programu i upewnij się, że je rozumiesz. Tutaj mam parametry typu alfa-przemianowany tak, że nie ma powodu do niejasność dwie rzeczy zarówno o nazwie U:

interface I<S, T> 
{ 
    I<S, T> M(); 
} 

class C<U, V> : I<U, V> 
{ 
    public I<U, V> M() {return null;} 
    public C<U, V> N() {return null;} 
} 

public class MainClass 
{ 
    public static void Main() 
    { 
     var i1 = typeof(I<,>); 
     var i2 = typeof(I<int, int>); 
     var i3 = i2.GetGenericTypeDefinition(); 
     var i4 = i1.GetMethod("M").ReturnType; 

     var c1 = typeof(C<,>); 
     var c2 = typeof(C<int, int>); 
     var c3 = c2.GetGenericTypeDefinition(); 
     var c4 = c1.GetMethod("N").ReturnType; 

     var i5 = c1.GetMethod("M").ReturnType; 
     var i6 = c1.GetInterfaces()[0]; 

     System.Console.WriteLine(i1 == i2); // false -- I<,> is not I<int, int> 
     System.Console.WriteLine(i1 == i3); // true -- I<int,int>'s decl is I<,> 
     System.Console.WriteLine(i1 == i4); // true -- I<,> is I<S, T> 
     System.Console.WriteLine(i1 == i5); // false -- I<S, T> is not I<U, V> 
     System.Console.WriteLine(i1 == i6); // false -- I<S, T> is not I<U, V> 

     System.Console.WriteLine(c1 == c2); // false -- C<,> is not C<int, int> 
     System.Console.WriteLine(c1 == c3); // true -- C<int,int>'s decl is C<,> 
     System.Console.WriteLine(c1 == c4); // true -- C<,> is C<U,V> 
    } 
} 
+0

Dzięki Eric, jesteś niesamowity. Zrozumiałem swój błąd, ale twój przykładowy kod jest świetny. Zgaduję, że mogę utworzyć typ, który chcę, przekazując ogólne argumenty klasy, aby GenericType zniknął z interfejsu - tj. 'T1.MakeGenericType (typeof (Something <,>) .GetGenericArguments())'. Czy mam rację? - Chociaż wiem, że to nie pomoże mi w moim pierwotnym problemie. – Iravanchi

+0

@ Nie ma za co. Nie uwierzyłbyś, że takie problemy, jak te, musimy rozwiązać w kompilatorze. Może to być bardzo mylące! –

+0

Czy mogę zadać jedno pytanie? Do tej pory nie zrobiłem wiele wokół Genrics, więc chciałbym wiedzieć, jakie są one dobre dla? Jaki jest w nich punkt (tworzenie, używanie ...)? thx za odpowiedź –

Powiązane problemy