Pergunta

Eu tenho uma interface definida como abaixo:

public interface TestInterface{
    int id { get; set; }
}

E dois Linq para SQL classes de implementação da interface:

public class tblTestA : TestInterface{
    public int id { get; set; }
}

public class tblTestB : TestInterface{
    public int id { get; set; }
}

Eu tenho IEnumerable listas a e b preenchido pelo banco de dados de registros de tblTestA e tblTestB

IEnumerable<tblTestA> a = db.tblTestAs.AsEnumerable();
IEnumerable<tblTestB> b = db.tblTestBs.AsEnumerable();

No entanto, o que se segue não é permitido:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a);
list.AddRange(b);

Eu faço da seguinte forma:

foreach(tblTestA item in a)
    list.Add(item)

foreach(tblTestB item in b)
    list.Add(item)

Existe algo que eu estou fazendo de errado?Obrigado por qualquer ajuda

Foi útil?

Solução

Isso funciona em C# 4, devido a genérico covariância.Ao contrário de versões anteriores do C#, é uma conversão do IEnumerable<tblTestA> para IEnumerable<TestInterface>.

A funcionalidade foi no CLR de v2, mas ele só foi exposto no C# 4 (e o quadro de tipos de não aproveitá-la antes .NET 4 também).Ele apenas aplica-se a interfaces genéricas e delegados (não em classes) e somente para os tipos de referência (portanto, não há conversão de IEnumerable<int> para IEnumerable<object> por exemplo.) Ele também só funciona onde faz sentido - IEnumerable<T> é covariante como objetos só vêm "de fora" da API, considerando que IList<T> é invariantes porque você pode adicionar valores com que a API também.

Genérico contravariância também é suportado, trabalhando em outra direção - por exemplo: você pode converter de IComparer<object> para IComparer<string>.

Se você não estiver usando o C# 4 e, em seguida, Tim sugestão de usar Enumerable.Cast<T> é um bom - você perde um pouco de rendimento, mas ele vai trabalhar.

Se você quiser saber mais sobre o genérico variância, Eric Lippert tem um longa série de posts sobre isso, e eu dei uma palestra sobre a NDC 2010, que você pode assistir no NDC página de vídeo.

Outras dicas

Você não está fazendo nada de errado: List<TestInterface>.AddRange espera um IEnumerable<TestInterface>.Ele não vai aceitar um IEnumerable<tblTestA> ou IEnumerable<tblTestB>.

O seu foreach loops de trabalho.Como alternativa, você pode usar Cast para alterar os tipos:

List<TestInterface> list = new List<TestInterface>();
list.AddRange(a.Cast<TestInterface>());
list.AddRange(b.Cast<TestInterface>());

O AddRange está à espera de uma lista de objetos de interface, e o seu "a" e "b" varaibles são definidos para ser uma lista de classe derivada de objetos.Obviamente, parece razoável que .NET poderia, logicamente, fazer com que saltar e tratá-los como uma lista de objetos de interface, porque eles, de fato, implementar a interface, que a lógica não era construir .NET através 3.5.

No entanto, esta capacidade (chamado de "covariância") foi adicionada .NET 4.0, mas até que você atualizar para isso, você vai ser preso com loop, ou talvez tentar chamar ToArray() e, em seguida, lançar o resultado de um TaskInterface[], ou talvez uma consulta LINQ para o caso de cada item e criar uma nova lista, etc.

a e b são do tipo IEnumerable<tblTestA> e IEnumerable<tblTestB>
Enquanto list.AddRange exigir que o parâmetro a ser do tipo IEnumerable<TestInterface>

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top