Não consigo entender por que o seguinte código C # não compila.
Como você pode ver, tenho um método genérico estático Something com um IEnumerable<T>
parâmetro (e T
está restrito a ser uma IA
interface) e esse parâmetro não pode ser convertido implicitamente para IEnumerable<IA>
.
Qual é a explicação? (Não procuro uma solução alternativa, apenas para entender por que ela não 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)
{
}
}
Erro que recebo na Something2(bar)
fila:
Argumento 1: não é possível converter de 'System.Collections.Generic.List' em 'System.Collections.Generic.IEnumerable'
c#
covariance
contravariance
BenLaz
fonte
fonte
T
a tipos de referência. Se você usar a condiçãowhere T: class, IA
, ela deve funcionar. A resposta vinculada tem mais detalhes.Something2(foo);
diretamente. Ir ao redor.ToList()
para obter umList<T>
(T
é o parâmetro de tipo declarado pelo método genérico) não é necessário para entender isso (aList<T>
é umIEnumerable<T>
).Respostas:
A mensagem de erro não é suficientemente informativa e a culpa é minha. Me desculpe por isso.
O problema que você está enfrentando é uma consequência do fato de que a covariância só funciona em tipos de referência.
Você provavelmente está dizendo "mas
IA
é um tipo de referência" agora. Sim, ele é. Mas você não disse queT
é igual aIA
. Você disse queT
é um tipo que implementaIA
, e um tipo de valor pode implementar uma interface . Portanto, não sabemos se a covariância funcionará e não a permitimos.Se você deseja que a covariância funcione, você deve informar ao compilador que o parâmetro de tipo é um tipo de referência com a
class
restrição, bem como aIA
restrição de interface.A mensagem de erro realmente deveria dizer que a conversão não é possível porque a covariância requer uma garantia de tipo de referência, uma vez que esse é o problema fundamental.
fonte
customers.Select(c=>c.FristName)
? A especificação C # deixa bem claro que se trata de um erro de resolução de sobrecarga : o conjunto de métodos aplicáveis denominado Select que pode aceitar esse lambda está vazio. Mas a causa raiz é queFirstName
tem um erro de digitação.Eu só queria complementar a excelente resposta interna de Eric com um exemplo de código para aqueles que podem não estar familiarizados com restrições genéricas.
Altere
Something
a assinatura da seguinte forma: Aclass
restrição tem que vir primeiro .fonte
primary_constraint ',' secondary_constraints ',' constructor_constraint
class
é ruim porque significa "tipo de referência", não "classe". Eu teria ficado mais feliz com algo prolixo comowhere T is not struct