Pergunta

Parece que um objeto List não pode ser armazenado em uma variável List em C# e nem pode ser explicitamente convertido 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> para System.Collections.Generic.List<object>

E então...

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> para System.Collections.Generic.List<object>

Claro, você pode fazer isso retirando tudo da lista de strings e colocando-os de volta, um de cada vez, mas é uma solução bastante complicada.

Foi útil?

Solução

Pense desta forma: se você fizesse tal conversão e depois adicionasse um objeto do tipo Foo à lista, a lista de strings não seria mais consistente.Se você iterasse a primeira referência, obteria uma exceção de conversão de classe porque, depois de atingir a instância Foo, o Foo não poderia ser convertido em string!

Como observação lateral, acho que seria mais significativo se você pudesse ou não fazer a conversão reversa:

List<object> ol = new List<object>();
List<string> sl;
sl = (List<string>)ol;

Faz algum tempo que não uso C#, então não sei se isso é legal, mas esse tipo de conversão é realmente (potencialmente) útil.Nesse caso, você está passando de uma classe mais geral (objeto) para uma classe mais específica (string) que se estende da geral.Dessa forma, se você adicionar strings à lista, não estará violando a lista de objetos.

Alguém sabe ou pode testar se tal conversão é legal em C#?

Outras dicas

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 funcionar.

Editar:Conforme observado por Zooba, você pode chamar ol.ToList() para obter uma lista

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 antes do 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 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();

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 voce diz List<string>() o compilador diz ListString() (que contém strings).[Pessoal técnico:esta é uma versão extremamente simples em inglês do que está acontecendo]

Conseqüentemente, obviamente o compilador não pode ser inteligente o suficiente para converter um ListString em um ListObject convertendo os itens de sua coleção interna.

É por isso que existem métodos de extensão para IEnumerable como Convert() que permitem fornecer facilmente conversão para os itens armazenados dentro de uma coleção, o que pode ser tão simples quanto converter de um para outro.

Isso tem muito a ver com 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 object.E como afirma Rex, o objeto List não converterá cada objeto para você.

Você pode tentar o código ff:

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 copiará (teoricamente) todo o conteúdo do sl sem problemas.

Sim, você pode, no .NET 3.5:

List<string> sl = new List<string>();
List<object> ol = sl.Cast<object>().ToList();

Mike - Acredito que a contravariância também não é permitida em C#

Ver Variação de parâmetro de tipo genérico no CLR para mais algumas informações.

Na verdade, isso é para que você não tente colocar nenhum "objeto" estranho em sua variante de lista "antiga" (como List<object> parece permitir) - porque seu código travaria (porque a lista realmente é List<string> e aceitará apenas 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 é uma lista de objetos em tempo de execução, e você realmente pode colocar qualquer objeto estranho em sua lista supostamente digitada estritamente.Procure por "genéricos reificados" para ver uma discussão mais ampla sobre o problema do Java...

Essa covariância em genéricos não é suportada, mas você pode fazer isso com matrizes:

object[] a = new string[] {"spam", "eggs"};

C# executa verificações em tempo de execução para evitar que você coloque, digamos, um int em a.

Aqui está outra solução pré-.NET 3.5 para qualquer IList cujo conteúdo possa ser convertido 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;
}

(Baseado no exemplo de Zooba)

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:

Leerlingen = (List<Leerling>)_DeserialiseerLeerlingen._TeSerialiserenObjecten.Cast<Leerling>();

.Cast para o tipo que você deseja obter IEnumerable desse tipo, então typecast o IEnemuerable para o List<> você quer.

Mm, graças aos comentários anteriores, encontrei duas maneiras de descobrir.O primeiro é obter a lista de strings de elementos e depois convertê-la para a lista de objetos IEnumerable:

IEnumerable<object> ob;
List<string> st = new List<string>();
ob = st.Cast<object>();

E a segunda é evitar o tipo de objeto IEnumerable, apenas convertendo a string para o tipo de objeto e depois usando a função "toList()" na mesma frase:

List<string> st = new List<string>();
List<object> ob = st.Cast<object>().ToList();

Eu gosto mais da segunda maneira.Eu espero que isso ajude.

List<string> sl = new List<string>();
List<object> ol;
ol = new List<object>(sl);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top