Parece que um objeto List não pode ser armazenado em uma variável List em C # e nem pode ser convertido explicitamente dessa forma.
List<string> sl = new List<string>();
List<object> ol;
ol = sl;
resulta em não é possível converter implicitamente o tipo System.Collections.Generic.List<string>
paraSystem.Collections.Generic.List<object>
E depois...
List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;
resulta em Não é possível converter o tipo System.Collections.Generic.List<string>
paraSystem.Collections.Generic.List<object>
Claro, você pode fazer isso retirando tudo da lista de strings e colocando de volta um de cada vez, mas é uma solução bastante complicada.
c#
.net
generics
covariance
type-safety
Matt Sheppard
fonte
fonte
Respostas:
Pense desta forma, se você fosse fazer tal conversão e, em seguida, adicionar um objeto do tipo Foo à lista, a lista de strings não seria mais consistente. Se você iterar a primeira referência, obterá uma exceção de conversão de classe porque, uma vez que você acerta a instância Foo, o Foo não pode ser convertido em string!
Como observação lateral, acho que seria mais significativo se você pudesse ou não fazer o cast reverso:
List<object> ol = new List<object>(); List<string> sl; sl = (List<string>)ol;
Eu não uso o C # há algum tempo, então não sei se isso é legal, mas esse tipo de elenco é na verdade (potencialmente) útil. Neste caso, você está indo de uma classe (objeto) mais geral para uma classe mais específica (string) que se estende da classe geral. Dessa forma, se você adicionar à lista de strings, não estará violando a lista de objetos.
Alguém sabe ou pode testar se tal elenco é legal em C #?
fonte
ol
houvesse algo que não fosse uma string, suponho que esperaria que o elenco falhasse no tempo de execução. Mas onde você realmente teria problemas é se o elenco tivesse sucesso, e então algo fosse adicionado aol
isso não é uma corda. Como fazsl
referência ao mesmo objeto, agora seuList<string>
conteria uma não string. EsteAdd
é o problema, que eu acho que justifica porque este código não compila, mas ele irá compilar se você mudarList<object> ol
paraIEnumerable<object> ol
, que não tem umAdd
. (Eu verifiquei isso em C # 4.)InvalidCastException
porque o tipo de tempo de execução deol
ainda estáList<object>
.Se você estiver usando o .NET 3.5, dê uma olhada no método Enumerable.Cast. É um método de extensão para que você possa chamá-lo diretamente na Lista.
List<string> sl = new List<string>(); IEnumerable<object> ol; ol = sl.Cast<object>();
Não é exatamente o que você pediu, mas deve servir.
Edit: Conforme observado por Zooba, você pode chamar ol.ToList () para obter uma lista
fonte
Você não pode converter entre tipos genéricos com parâmetros de tipo diferentes. Tipos genéricos especializados não fazem parte da mesma árvore de herança e, portanto, são tipos não relacionados.
Para fazer isso pré-NET 3.5:
List<string> sl = new List<string>(); // Add strings to sl List<object> ol = new List<object>(); foreach(string s in sl) { ol.Add((object)s); // The cast is performed implicitly even if omitted }
Usando o Linq:
var sl = new List<string>(); // Add strings to sl var ol = new List<object>(sl.Cast<object>()); // OR var ol = sl.Cast<object>().ToList(); // OR (note that the cast to object here is required) var ol = sl.Select(s => (object)s).ToList();
fonte
A razão é que uma classe genérica como
List<>
é, para a maioria dos propósitos, tratada externamente como uma classe normal. por exemplo, quando você dizList<string>()
o compilador dizListString()
(que contém strings). [Pessoal técnico: esta é uma versão inglesa extremamente simples do que está acontecendo]Conseqüentemente, obviamente o compilador não pode ser inteligente o suficiente para converter um ListString em um ListObject lançando os itens de sua coleção interna.
É por isso que existem métodos de extensão para IEnumerable como Convert () que permitem que você forneça facilmente a conversão para os itens armazenados dentro de uma coleção, o que poderia ser tão simples quanto converter um para outro.
fonte
Isso tem muito a ver com a covariância, por exemplo, tipos genéricos são considerados parâmetros e, se os parâmetros não forem resolvidos adequadamente para um tipo mais específico, a operação falhará. A implicação disso é que você realmente não pode lançar para um tipo mais geral, como objeto. E conforme afirmado por Rex, o objeto List não converterá cada objeto para você.
Você pode tentar o código ff em vez disso:
List<string> sl = new List<string>(); //populate sl List<object> ol = new List<object>(sl);
ou:
List<object> ol = new List<object>(); ol.AddRange(sl);
ol irá (teoricamente) copiar todo o conteúdo do sl sem problemas.
fonte
Sim, você pode, no .NET 3.5:
List<string> sl = new List<string>(); List<object> ol = sl.Cast<object>().ToList();
fonte
Mike - Eu acredito que a contravariância também não é permitida em C #
Consulte Variância de parâmetro de tipo genérico no CLR para mais informações.
fonte
Acho que isso (contravariância) será realmente suportado no C # 4.0. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
fonte
Isso é realmente para que você não tente colocar qualquer "objeto" estranho em sua "velha" variante de lista (como
List<object>
parece permitir) - porque seu código travaria então (porque a lista realmente éList<string>
e só aceitará objetos do tipo String ) É por isso que você não pode converter sua variável para uma especificação mais geral.Em Java é o contrário, você não tem genéricos e, em vez disso, tudo é Lista de objetos em tempo de execução, e você realmente pode colocar qualquer objeto estranho em sua Lista supostamente digitada com rigidez. Pesquise por "Reified generics" para ver uma discussão mais ampla sobre o problema de java ...
fonte
Essa covariância em genéricos não é suportada, mas você pode realmente fazer isso com matrizes:
object[] a = new string[] {"spam", "eggs"};
C # executa verificações de tempo de execução para evitar que você coloque, digamos, um
int
ema
.fonte
Aqui está outra solução pré-.NET 3.5 para qualquer IList cujo conteúdo pode ser lançado implicitamente.
public IList<B> ConvertIList<D, B>(IList<D> list) where D : B { List<B> newList = new List<B>(); foreach (D item in list) { newList.Add(item); } return newList; }
(Com base no exemplo de Zooba)
fonte
Eu tenho um:
private List<Leerling> Leerlingen = new List<Leerling>();
E eu iria preenchê-lo com dados coletados em um.
List<object>
O que finalmente funcionou para mim foi este:.Cast
para o tipo que você deseja obterIEnumerable
desse tipo e, em seguida, digite oIEnemuerable
para o tipoList<>
desejado.fonte
Mm, graças aos comentários anteriores, encontrei duas maneiras de descobrir isso. O primeiro é obter a lista de strings de elementos e, em seguida, lançá-la na lista de objetos IEnumerable:
IEnumerable<object> ob; List<string> st = new List<string>(); ob = st.Cast<object>();
E o segundo é evitar o tipo de objeto IEnumerable, apenas convertendo a string para o tipo de objeto e, em seguida, usando a função "toList ()" na mesma frase:
List<string> st = new List<string>(); List<object> ob = st.Cast<object>().ToList();
Gosto mais da segunda forma. Eu espero que isso ajude.
fonte
List<string> sl = new List<string>(); List<object> ol; ol = new List<object>(sl);
fonte