Error de conversión de tipo C # a pesar de la restricción genérica
-
06-07-2019 - |
Pregunta
Por qué, con una restricción genérica en el parámetro de tipo T de la clase P de & "; debe heredar de A &"; ¿la primera llamada tiene éxito pero la segunda llamada falla con el error de conversión de tipo detallado en el comentario:
abstract class A { }
static class S
{
public static void DoFirst(A argument) { }
public static void DoSecond(ICollection<A> argument) { }
}
static class P<T>
where T : A, new()
{
static void Do()
{
S.DoFirst(new T()); // this call is OK
S.DoSecond(new List<T>()); // this call won't compile with:
/* cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.ICollection<A>' */
}
}
¿No debería la restricción genérica garantizar que List<T>
sea en verdad ICollection<A>
?
Solución
Este es un ejemplo de la falta de C # de covarianza en tipos genéricos (C # sí admite covarianza de matriz). C # 4 agregará esta característica en los tipos de interfaz y también actualizará varios tipos de interfaz BCL para admitirla también.
Consulte C # 4.0: Covarianza y Contravarianza :
En este artículo, & # 8217; intentaré cubrir uno de las innovaciones de C # 4.0. Uno de los nuevas características es la covarianza y contravarianza en los parámetros de tipo que ahora es apoyado por delegados genéricos e interfaces genéricas. Primero dejemos & # 8217; s mira qué significan estas palabras :)
Otros consejos
La restricción no tiene efecto sobre el problema; el problema es que está pasando una Lista en un parámetro que requiere ICollection: C # no admite covarianza, por lo que debe emitir explícitamente la lista a una ICollection:
S.DoSecond((ICollection<A>) new List<T>()); // this call will be happy
Ha escrito fuertemente el parámetro para DoSecond como tipo ICollection < A > ;. A pesar de que T es de tipo A, en el momento de la compilación no hay una conversión implícita entre List & Lt; T & Gt; e ICollection < A > ;. Deberá crear la lista y enviarla a ICollection & Lt; A & Gt; cuando llama a DoSecond, o hace de DoSecond un método genérico en sí mismo.
NOTA: Este tipo de conversión implícita debe ser compatible con C # 4.0, lo que proporcionará una co / contravarianza mucho mejor sobre lo que ofrece C # 3.0.