No puedo entender por qué el siguiente código C # no se compila.
Como puede ver, tengo un método genérico estático Algo con un IEnumerable<T>
parámetro (y T
está restringido a ser una IA
interfaz), y este parámetro no se puede convertir implícitamente a IEnumerable<IA>
.
Cual es la explicacion (No busco una solución alternativa, solo para entender por qué no funciona).
public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }
public static class Test
{
public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
{
var bar = foo.ToList();
// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());
// This call is illegal
Something2(bar);
return bar;
}
private static void Something2(IEnumerable<IA> foo)
{
}
}
Error me pongo en Something2(bar)
línea:
Argumento 1: no se puede convertir de 'System.Collections.Generic.List' a 'System.Collections.Generic.IEnumerable'
c#
covariance
contravariance
BenLaz
fuente
fuente
T
a los tipos de referencia. Si usa la condición,where T: class, IA
entonces debería funcionar. La respuesta vinculada tiene más detalles.Something2(foo);
directamente. No es necesario dar vueltas.ToList()
para obtener unList<T>
(T
es su parámetro de tipo declarado por el método genérico) para comprender esto (aList<T>
es unIEnumerable<T>
).Respuestas:
El mensaje de error es insuficientemente informativo y es culpa mía. Lo siento por eso.
El problema que está experimentando es una consecuencia del hecho de que la covarianza solo funciona en tipos de referencia.
Probablemente estés diciendo "pero
IA
es un tipo de referencia" en este momento. Sí lo es. Pero no dijiste que esoT
es igual aIA
. Dijiste queT
es un tipo que implementaIA
y un tipo de valor puede implementar una interfaz . Por lo tanto, no sabemos si la covarianza funcionará y la rechazamos.Si desea que la covarianza funcione, debe decirle al compilador que el parámetro de tipo es un tipo de referencia con la
class
restricción y laIA
restricción de interfaz.El mensaje de error realmente debería decir que la conversión no es posible porque la covarianza requiere una garantía de tipo de referencia, ya que ese es el problema fundamental.
fuente
customers.Select(c=>c.FristName)
? La especificación de C # es muy clara en cuanto a que se trata de un error de resolución de sobrecarga : el conjunto de métodos aplicables denominado Select que puede tomar esa lambda está vacío. Pero la causa principal es queFirstName
tiene un error tipográfico.Solo quería complementar la excelente respuesta privilegiada de Eric con un ejemplo de código para aquellos que pueden no estar tan familiarizados con las restricciones genéricas.
Something
La firma del cambio es así: laclass
restricción tiene que ser lo primero .fuente
primary_constraint ',' secondary_constraints ',' constructor_constraint
class
es malo porque significa "tipo de referencia", no "clase". Hubiera sido más feliz con algo detallado comowhere T is not struct