Lista de elenco <T> para listar <Interface>


109
public interface IDic
{
    int Id { get; set; }
    string Name { get; set; }
}
public class Client : IDic
{

}

Como posso transmitir List<Client>para List<IDic>?

Respostas:


249

Você não pode lançá- lo (preservando a identidade de referência) - isso não seria seguro. Por exemplo:

public interface IFruit {}

public class Apple : IFruit {}
public class Banana : IFruit {}

...

List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());

// Eek - it's a banana!
Apple apple = apples[0];

Agora você pode converter List<Apple>a IEnumerable<IFruit>em .NET 4 / C # 4 devido à covariância, mas se quiser, List<IFruit>terá que criar uma nova lista. Por exemplo:

// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();

// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();

Mas isso não é o mesmo que lançar a lista original - porque agora existem duas listas separadas . Isso é seguro, mas você precisa entender que as alterações feitas em uma lista não serão vistas na outra lista. (Modificações nos objetos aos quais as listas se referem serão vistas, é claro.)


6
como se eles ainda estivessem no prédio!
Andras Zoltan

1
Qual é a diferença entre fazer a covariância tolist e fazer new List <IFruit> (); em seguida, foreach sobre a lista original e adicionar cada item à lista IFruit? Na forma foreach ... a referência do objeto seria a mesma, correto? Então ... se isso for verdade, não faz muito sentido para mim pessoalmente que você não possa simplesmente lançar a lista inteira diretamente. ?
Robert Noack

3
@RobertNoack: O que você quer dizer com "a referência do objeto"? A referência de objeto de cada elemento é a mesma, mas não é o mesmo que lançar a própria referência de lista. Suponha que você pudesse lançar a referência, de forma que você tivesse uma referência do tipo de tempo de compilação List<IFruit>que era na verdade uma referência a a List<Apple>. O que você esperaria que acontecesse se adicionasse uma Bananareferência a isso List<IFruit>?
Jon Skeet

1
Oh. Acho que preciso aprender a ler. Achei que a resposta original dizia que os objetos da lista seriam copiados e recriados em profundidade, o que não fazia sentido para mim. Mas eu claramente perdi a parte em que apenas uma nova lista é criada com os mesmos objetos.
Robert Noack

2
@ TrươngQuốcKhánh: Eu não tenho idéia do que qualquer de seus olhares de código, como, ou se você tiver uma usingdirectiva para System.Linq, ou o que você está tentando chamá-lo, eu não sei como você espera que eu seja capaz de ajudar. Eu sugiro que você faça mais pesquisas e, se ainda estiver preso, faça uma pergunta com um exemplo reproduzível mínimo .
Jon Skeet

6

Um iterador Cast e .ToList ():

List<IDic> casted = input.Cast<IDic>().ToList() vai fazer o truque.

Originalmente, eu disse que a covariância funcionaria - mas, como Jon corretamente apontou; não, não vai!

E originalmente eu também estupidamente à esquerda para fora da ToList()chamada


Castretorna um IEnumerable<T>, não um List<T>- e não, a covariância não permitirá essa conversão, porque não seria seguro - veja minha resposta.
Jon Skeet

Na página que você vinculou a: "Somente tipos de interface e tipos de delegado podem ter parâmetros de tipo variante"
Jon Skeet

@Jon - Percebi que ToList()estava faltando antes de ler seu comentário; mas sim, como você mostrou, claro que a covariância não funcionará! Doh!
Andras Zoltan

Certo. A covariância ainda pode ajudar, pois significa que você não precisa da Castchamada no .NET 4, desde que especifique o argumento de tipo para ToList.
Jon Skeet

5

Eu também tive esse problema e depois de ler a resposta de Jon Skeet, modifiquei meu código de uso List<T>para uso IEnumerable<T>. Embora isso não responda à pergunta original do OP de como posso lançar List<Client>paraList<IDic> , evita a necessidade de fazê-lo e, portanto, pode ser útil para outras pessoas que enfrentam esse problema. É claro que isso pressupõe que o código que requer o uso de List<IDic>está sob seu controle.

Por exemplo:

public void ProcessIDic(IEnumerable<IDic> sequence)
{
   // Implementation
}

Ao invés de:

public void ProcessIDic(List<IDic> list)
{
   // Implementation
}

3

Se você pode usar o LINQ, você pode fazer isso ...

List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();

3
List<Client> listOfA = new List<Client>();
List<IDic> list = listOfA.Cast<IDic>().ToList();

0

Só é possível criando novos List<IDic>e transferindo todos os elementos.


Algum comentário por que não votou, já que o significado geral é o mesmo que todas as outras respostas?
Piotr Auguscik

Meu palpite é que você foi reprovado porque disse que só era possível criar uma nova lista, mas outros postaram ao contrário ... mas não meu downvote)
musefan

Bem, eles criam novas listas, mas não com um novo operador, o que não muda o fato de que eles fazem.
Piotr Auguscik

0

No .Net 3.5, você pode fazer o seguinte:

List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());

O construtor de List neste caso leva um IEnumerable.
lista, porém, só é conversível para IEnumerable. Mesmo que myObj possa ser conversível em ISomeInterface, o tipo IEnumerable não é conversível em IEnumerable.


O problema é que isso faz uma cópia da lista, na maioria das vezes você deseja fazer operações na lista original
rola em
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.