2011-11-08 15 views
7

¿Es posible implementar una clase restringida a dos parámetros genéricos únicos?Una clase genérica con dos tipos no iguales (únicos)

Si no es así, ¿es porque no se ha implementado o porque sería imposible dada la estructura del lenguaje (herencia)?

me gustaría algo de la forma:

class BidirectionalMap<T1,T2> where T1 != T2 
{ 
    ... 
} 

Me estoy poniendo en práctica un Bidirectional dictionary. Esto es principalmente una cuestión de curiosidad, no de necesidad.


Parafraseado de los comentarios:

  1. Dan: "¿Cuáles son las consecuencias negativas si no se cumple esta limitación"

  2. Yo: "Entonces el usuario podría indexar con el mapa [t1] y el mapa [t2]. Si fueran del mismo tipo, no habría distinción y no tendría ningún sentido".

  3. Dan: El compilador realmente permite [dos parámetros de tipo genérico para definir sobrecargas de método distintas], así que tengo curiosidad; ¿elige arbitrariamente uno de los métodos para llamar?

+1

Siempre puede lanzar un 'nuevo ShouldBeCompileTimeError()' en el constructor . :-) – foson

+1

probablemente porque no tiene sentido, son genéricos, algo que no debería estar "restringido" por tipos. – GriffinHeart

+0

Por curiosidad, ¿cuál es la consecuencia negativa si no se cumple esta restricción? Una asignación entre objetos del mismo conjunto es un requisito muy común. –

Respuesta

4

Ampliando el ejemplo para poner de relieve el problema:

public class BidirectionalMap<T1,T2> 
{ 
    public void Remove(T1 item) {} 
    public void Remove(T2 item) {} 

    public static void Test() 
    { 
     //This line compiles 
     var possiblyBad = new BidirectionalMap<string, string>(); 

     //This causes the compiler to fail with an ambiguous invocation 
     possiblyBad.Remove("Something"); 
    } 
} 

Así que la respuesta es que, a pesar de que no se puede especificar la restricción T1 = T2, no importa, porque el compilador fallará tan pronto como intente hacer algo que viole la restricción implícita. Todavía detecta el error en tiempo de compilación, por lo que puede utilizar estas sobrecargas con impunidad. Es un poco extraño, ya que puede crear una instancia del mapa (e incluso podría escribir código de IL que manipula el mapa de forma apropiada), pero el compilador de C# no le permitirá causar estragos resolviendo arbitrariamente sobrecargas ambiguas.


Una nota lateral es que este tipo de sobrecarga podría causar comportamientos extraños si no tiene cuidado. Si usted tiene un BidirectionalMap<Animal, Cat> y gato: Animal, tenga en cuenta lo que sucederá con este código:

Animal animal = new Cat(); 
map.Remove(animal); 

Esto llamará a la sobrecarga que lleva animal, por lo que tratará de eliminar una clave, a pesar de que podría haber destinado a eliminar el valor Cat. Este es un caso algo artificial, pero es suficiente para garantizar precaución cuando se producen comportamientos muy diferentes como resultado de la sobrecarga de métodos. En tales casos, probablemente sea más fácil de leer y mantener si solo le da diferentes nombres a los métodos, reflejando sus diferentes comportamientos (RemoveKey y RemoveValue, digamos).

+0

Excelente respuesta de raíz Texto de error:' La llamada es ambigua entre los siguientes métodos o propiedades: BidirectionalMap .this [T] 'y' BidirectionalMap . this [K] '" – user664939

0

Las limitaciones de tipo parecen ser un nombre inapropiado. Si bien contrain lo que el parámetro de tipo es, el propósito es dejar que el compilador sepa qué operaciones están disponibles para el tipo.
Si lo desea, puede tener una restricción donde T1 y T2 derivan de clases de base de concreto separadas, pero no creo que eso sea exactamente lo que desea.

-1

No hay una manera efectiva de hacer esto sin imponer ninguna otra restricción sobre los tipos mismos. Como señaló otra persona, podría hacer restricciones que los dos tipos derivan de dos clases base diferentes, pero probablemente no sea muy bueno desde el punto de vista del diseño.

Editado para agregar: la razón por la que esto no se implementa es muy probable porque nadie en Microsoft alguna vez consideró que algo como esto fuera necesario aplicar en tiempo de compilación, a diferencia de las otras restricciones que tienen que ver con la capacidad real usar variables de los tipos especificados. Y como algunos comentaristas han señalado, ciertamente puede hacer cumplir esto en tiempo de ejecución.

0

La desigualdad no ayudaría al compilador a detectar errores. Cuando especifica restricciones en los parámetros de tipo, le está diciendo al compilador que las variables de este tipo siempre admitirán una determinada interfaz o se comportarán de ciertas maneras. Cada uno de ellos le permite al compilador validar algo más como "este método estará presente para que pueda invocarse en T".

La desigualdad de los parámetros de tipo sería más como validar que los argumentos del método no son nulos. Es parte de la lógica del programa, no su tipo de seguridad.

0

No estoy del todo seguro de por qué esta sería una verificación de tiempo de compilación deseable. Sería posible pasar por alto la condición al encapsular la clave o el valor, haciendo inútil la verificación en tiempo de compilación.

Se debe tener en cuenta ... ¿qué errores estoy tratando de evitar?

Si simplemente está impidiendo que un compañero de trabajo perezoso no lea la documentación, agregue una verificación de solo depuración y genere una excepción. De esta forma, se puede eliminar el cheque para el código de liberación, p.

#if Debug 

if (T1 is T2 || T2 is T1) 
{ 
    throw new ArguementException(...); 
} 

#endif 

Si usted está tratando de evitar que una persona malévola el uso de la biblioteca de una manera no intencionada, entonces tal vez es necesaria una comprobación en tiempo de ejecución, de lo contrario, sería fácil a la caja de la clave o valor.

+0

También puede poner esta marca en el constructor estático del tipo genérico , por lo tanto, solo se ejecutará una vez. (Por cierto, su cheque no compilará, porque el lado izquierdo del operador 'is' toma una referencia de objeto, no un nombre de tipo. Quiere' if (typeof (T1) = = typeof (t2) ') – phoog

0

No, no puede usar la igualdad (o la desigualdad) como una restricción. En pocas palabras, la igualdad no es una restricción, sino una condición. Debe probar una condición , como igualdad o desigualdad de tipos en el constructor y lanzar una excepción apropiada.

Cuestiones relacionadas