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 Testá restringido a ser una IAinterfaz), 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

Ta los tipos de referencia. Si usa la condición,where T: class, IAentonces debería funcionar. La respuesta vinculada tiene más detalles.Something2(foo);directamente. No es necesario dar vueltas.ToList()para obtener unList<T>(Tes 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
IAes un tipo de referencia" en este momento. Sí lo es. Pero no dijiste que esoTes igual aIA. Dijiste queTes un tipo que implementaIAy 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
classrestricción y laIArestricció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 queFirstNametiene 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.
SomethingLa firma del cambio es así: laclassrestricción tiene que ser lo primero .fuente
primary_constraint ',' secondary_constraints ',' constructor_constraintclasses malo porque significa "tipo de referencia", no "clase". Hubiera sido más feliz con algo detallado comowhere T is not struct