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>?

¿Fue útil?

Solución

Este es un ejemplo de la falta de C # de covarianza en tipos genéricos (C # 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top