Eu sei que é possível converter uma lista de itens de um tipo para outro (considerando que seu objeto tem um método de operador explícito estático público para fazer a conversão), um de cada vez, da seguinte maneira:
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
Mas não é possível transmitir a lista inteira de uma só vez? Por exemplo,
ListOfY = (List<Y>)ListOfX;
c#
list
casting
ienumerable
Jimbo
fonte
fonte
Respostas:
Se
X
realmente pode ser transmitido paraY
você, você deve poder usarAlgumas coisas para estar ciente (H / T para comentaristas!)
using System.Linq;
para obter esse método de extensãoList<Y>
será criado pela chamada paraToList()
.fonte
Cast<T>
método não suporta operadores de conversão personalizados. Por que o Linq Cast Helper não funciona com o operador implícito de conversão .A conversão direta
var ListOfY = (List<Y>)ListOfX
não é possível porque exigiria co-contravariância doList<T>
tipo e isso simplesmente não pode ser garantido em todos os casos. Leia para ver as soluções para esse problema de fundição.Embora pareça normal ser capaz de escrever código como este:
porque podemos garantir que todo mamífero será um animal, isso é obviamente um erro:
já que nem todo animal é um mamífero.
No entanto, usando C # 3 e acima, você pode usar
isso facilita um pouco o elenco. Isso é sintaticamente equivalente ao seu código de adição um por um, pois usa uma conversão explícita para converter cada um
Mammal
da lista em umaAnimal
e falhará se a conversão não for bem-sucedida.Se você quiser ter mais controle sobre o processo de conversão / conversão, use o
ConvertAll
método daList<T>
classe, que pode usar uma expressão fornecida para converter os itens. Ele tem o benefício adicional de retornar aList
, em vez deIEnumerable
, portanto não.ToList()
é necessário.fonte
Para adicionar ao ponto de Sweko:
A razão pela qual o elenco
isso não é possível porque
List<T>
é invariável no Tipo T e, portanto, não importa seX
deriva deY
) - isso ocorre porqueList<T>
é definido como:(Observe que nesta declaração, digite
T
aqui não possui modificadores de variação adicionais)No entanto, se coleções mutáveis não forem necessárias em seu design, é possível fazer upcast em muitas das coleções imutáveis , por exemplo, desde que
Giraffe
derivadas deAnimal
:Isso ocorre porque
IEnumerable<T>
suporta covariância emT
- isso faz sentido, poisIEnumerable
implica que a coleção não pode ser alterada, pois não possui suporte para métodos para adicionar ou remover elementos da coleção. Observe aout
palavra - chave na declaração deIEnumerable<T>
:( Aqui está mais uma explicação do motivo pelo qual coleções mutáveis como
List
não podem suportarcovariance
, enquanto iteradores e coleções imutáveis podem.)Fundição com
.Cast<T>()
Como outros já mencionaram,
.Cast<T>()
pode ser aplicado a uma coleção para projetar uma nova coleção de elementos convertidos para T, no entanto, isso será acionadoInvalidCastException
se a conversão em um ou mais elementos não for possível (o que seria o mesmo comportamento que o explícito noforeach
loop do OP ).Filtragem e conversão com
OfType<T>()
Se a lista de entrada contiver elementos de tipos diferentes e incompatíveis, o potencial
InvalidCastException
poderá ser evitado usando em.OfType<T>()
vez de.Cast<T>()
. (.OfType<>()
verifica se um elemento pode ser convertido no tipo de destino, antes de tentar a conversão, e filtra tipos incompatíveis.)para cada
Observe também que, se o OP tivesse escrito isso: (observe o explícito
Y y
noforeach
)que o elenco também será tentado. No entanto, se nenhuma conversão for possível,
InvalidCastException
haverá um resultado.Exemplos
Por exemplo, dada a hierarquia de classes simples (C # 6):
Ao trabalhar com uma coleção de tipos mistos:
Enquanto que:
filtra apenas os elefantes - ou seja, as zebras são eliminadas.
Operadores implícitos de elenco
Sem dinâmica, os operadores de conversão definidos pelo usuário são usados apenas em tempo de compilação *; portanto, mesmo que um operador de conversão entre o Zebra e o Elephant seja disponibilizado, o comportamento do tempo de execução acima das abordagens à conversão não mudaria.
Se adicionarmos um operador de conversão para converter uma Zebra em um elefante:
Em vez disso, dado o operador de conversão acima, o compilador poderá alterar o tipo da matriz abaixo de
Animal[]
paraElephant[]
, pois as Zebras agora podem ser convertidas em uma coleção homogênea de elefantes:Usando operadores de conversão implícitos em tempo de execução
* Conforme mencionado por Eric, no entanto, o operador de conversão pode ser acessado em tempo de execução, recorrendo a
dynamic
:fonte
foreach
não filtra, mas usar um tipo mais derivado como variável de iteração forçará o compilador a tentar um Cast, que falhará no primeiro elemento que não estiver em conformidade.Você pode usar
List<Y>.ConvertAll<T>([Converter from Y to T]);
fonte
Esta não é a resposta a esta pergunta, mas pode ser útil para alguns: como disse @SWeko, graças a covariância e contravariance,
List<X>
não pode ser convertido emList<Y>
, masList<X>
pode ser lançadoIEnumerable<Y>
, e mesmo com conversão implícita.Exemplo:
mas
A grande vantagem é que ele não cria uma nova lista na memória.
fonte
fonte