2011-07-15 20 views
7

Cuando tenemos algo como esto:Cómo crear un tipo genérico construido sin especificar ningún tipo de parámetros

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

typeof(ISomething<,>) y typeof(Something<,>) se traducirá en una "definición de tipo genérico". Pero si llegamos al tipo de interfaz como la interfaz implementada por la clase, que será un tipo construido, que ninguno de sus parámetros de tipo son en realidad obligado:

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

MSDN menciona específicamente. Lo que quiero es construir el mismo tipo (tipo construido) de ISomething<,> directamente (sin subclasificarlos y buscar el tipo de base), y no pude encontrar ninguna manera de hacerlo.

Otros detalles:

Incluso he intentado esto:

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

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

En el código anterior:

t1.Equals(t2) es cierto, pero t1.Equals(t3) es falso, obviamente porque t3 se construye.

Sorprendentemente, t1.GetGenericArguments()[0].Equals(t3.GetGenericArguments()[0]) es falso, aunque ambos están abiertos (IsGenericParameter = true), y no pude encontrar ninguna diferencia en sus propiedades.

Y esta es la razón por la que necesito hacer esto: Necesito una forma canónica de almacenar objetos de tipo en una lista. Los objetos a veces provienen de clases/interfaces base (como t3 arriba) y algunas veces directamente (como t1). Tendré que ser capaz de compararlos entre sí. No puedo almacenar la definición de tipo genérico (usando .GetGenericTypeDefinition()) porque a veces tendré un tipo genérico parcialmente abierto (como ISomething) y GetGenericTypeDefinition me dará un tipo sin ningún tipo de argumento especificado.

La única manera de hacer que los tipos sean canónicos que pensé que podrían funcionar, es comprobar si todos los argumentos de tipo están libres, y hacer una GetGenericTypeDefinition. De lo contrario, mantenga el tipo construido.

+0

No creo que esto funciona: "comprobar si todos los argumentos son de tipo no unido y haz una GetGenericTypeDefinition. De lo contrario, conserva el tipo construido ". Supongamos que el tipo que tiene es 'I '. Todos los argumentos de tipo son parámetros de tipo independiente, pero ese es un tipo diferente que 'I '. –

+2

Re: "Sorprendentemente ..." - esto no es sorprendente en absoluto. Sospecho que parte de la confusión de todo esto es que tienes dos tipos completamente diferentes llamados "U" y dos tipos completamente diferentes llamados "V". Por supuesto 'I <,>' es diferente de 'I ' en la lista de interfaz implementada; el primero se parametriza con el '' declarado por 'I', y el otro se parametriza con' 'declarado por' Something'. El hecho de que los parámetros de tipo tengan los mismos nombres no los convierte en el mismo tipo. –

+0

Si tengo un 'I ' construido, y lo llamo GetGenericTypeDefinition(), ¿me dará 'typeof (I )'? – Iravanchi

Respuesta

4

Te estás haciendo un desastre aquí. Examine el resultado de este programa y asegúrese de comprenderlo. Aquí he alfa-renombrado los parámetros de tipo de modo que no hay falta de claridad debido a dos cosas a la vez nombrados T:

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

Gracias Eric, eres increíble. Me di cuenta de mi error, pero tu código de muestra es genial. Creo que puedo hacer el tipo que quiero pasando los argumentos genéricos de la clase para hacer que GenericType salga de la interfaz, es decir, 't1.MakeGenericType (typeof (Something <,>) .GetGenericArguments())'. ¿Estoy en lo cierto? - Aunque, sé que esto no me ayudará en mi problema original. – Iravanchi

+0

@ De nada. No creería el tipo de problemas como este que tenemos que resolver en el compilador. ¡Puede ser muy confuso! –

+0

¿Puedo hacer una pregunta? Hasta ahora no he hecho mucho en torno a Genrics, entonces me gustaría saber para qué sirven. ¿Cuál es el punto en ellos (crear, usar ...)? THX para la respuesta –

Cuestiones relacionadas