Sé que es posible emitir una lista de elementos de un tipo a otro (dado que su objeto tiene un método de operador explícito estático público para realizar la conversión) uno a la vez de la siguiente manera:
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
Pero, ¿no es posible emitir la lista completa al mismo tiempo? Por ejemplo,
ListOfY = (List<Y>)ListOfX;
c#
list
casting
ienumerable
Jimbo
fuente
fuente
Respuestas:
Si
X
realmente se te puede lanzarY
, deberías poder usarAlgunas cosas a tener en cuenta (¡H / T a los comentaristas!)
using System.Linq;
para obtener este método de extensiónList<Y>
creará un nuevo por la llamada aToList()
.fuente
Cast<T>
método no admite operadores de conversión personalizados. ¿Por qué el Linq Cast Helper no funciona con el operador de transmisión implícito ?El lanzamiento directo
var ListOfY = (List<Y>)ListOfX
no es posible porque requeriría co / contravarianza delList<T>
tipo, y eso no puede garantizarse en todos los casos. Siga leyendo para ver las soluciones a este problema de transmisión.Si bien parece normal poder escribir código como este:
porque podemos garantizar que cada mamífero será un animal, esto obviamente es un error:
ya que no todos los animales son mamíferos.
Sin embargo, usando C # 3 y superior, puede usar
eso facilita un poco el lanzamiento. Esto es sintácticamente equivalente a su código de adición uno por uno, ya que utiliza un reparto explícito para convertir cada uno
Mammal
en la lista en unAnimal
, y fallará si el reparto no tiene éxito.Si desea tener más control sobre el proceso de conversión / conversión, puede usar el
ConvertAll
método de laList<T>
clase, que puede usar una expresión proporcionada para convertir los elementos. Tiene el beneficio añadido de que devuelve unList
, en lugar deIEnumerable
, por lo que no.ToList()
es necesario.fuente
Para agregar al punto de Sweko:
La razón por la cual el elenco
no es posible porque
List<T>
es invariante en el Tipo T y, por lo tanto, no importa si seX
deriva deY
), esto se debe a queList<T>
se define como:(Tenga en cuenta que en esta declaración, escriba
T
aquí no tiene modificadores de varianza adicionales)Sin embargo, si no se requieren colecciones mutables en su diseño, es posible una transmisión ascendente en muchas de las colecciones inmutables , por ejemplo, siempre que se
Giraffe
derive deAnimal
:Esto se debe a que
IEnumerable<T>
admite la covarianzaT
: esto tiene sentido dado queIEnumerable
implica que la colección no se puede cambiar, ya que no admite métodos para Agregar o quitar elementos de la colección. Tengaout
en cuenta la palabra clave en la declaración deIEnumerable<T>
:( Aquí hay una explicación más detallada de la razón por la cual las colecciones mutables como
List
no pueden soportarcovariance
, mientras que los iteradores y colecciones inmutables sí pueden).Fundición con
.Cast<T>()
Como otros han mencionado,
.Cast<T>()
se puede aplicar a una colección para proyectar una nueva colección de elementos lanzados a T, sin embargo, hacerlo arrojará un resultadoInvalidCastException
si no es posible lanzar uno o más elementos (lo que sería el mismo comportamiento que hacer lo explícito). emitido en elforeach
bucle del OP ).Filtrado y Fundición con
OfType<T>()
Si la lista de entrada contiene elementos de tipos diferentes e incompatibles,
InvalidCastException
se puede evitar el potencial utilizando en.OfType<T>()
lugar de.Cast<T>()
. (.OfType<>()
comprueba si un elemento se puede convertir al tipo de destino, antes de intentar la conversión, y filtra los tipos incompatibles).para cada
También tenga en cuenta que si el OP había escrito esto en su lugar: (tenga en cuenta lo explícito
Y y
en elforeach
)que también se intentará el casting. Sin embargo, si no es posible lanzar, se
InvalidCastException
obtendrá un resultado.Ejemplos
Por ejemplo, dada la jerarquía de clases simple (C # 6):
Al trabajar con una colección de tipos mixtos:
Mientras:
filtra solo los elefantes, es decir, se eliminan las cebras.
Re: operadores de reparto implícito
Sin dinámica, los operadores de conversión definidos por el usuario solo se usan en tiempo de compilación *, por lo que incluso si un operador de conversión entre, por ejemplo, Zebra y Elephant estuviera disponible, el comportamiento del tiempo de ejecución anterior de los enfoques de conversión no cambiaría.
Si agregamos un operador de conversión para convertir una cebra en un elefante:
En cambio, dado el operador de conversión anterior, el compilador podrá cambiar el tipo de la matriz a continuación de
Animal[]
aElephant[]
, dado que las cebras ahora se pueden convertir en una colección homogénea de elefantes:Uso de operadores de conversión implícita en tiempo de ejecución
* Como mencionó Eric, se puede acceder al operador de conversión en tiempo de ejecución recurriendo a
dynamic
:fuente
foreach
no se filtra, pero usar un tipo más derivado como la variable de iteración obligará al compilador a intentar un Cast, que fallará en el primer elemento que no cumpla.Puedes usar
List<Y>.ConvertAll<T>([Converter from Y to T]);
fuente
Esta no es exactamente la respuesta a esta pregunta, pero puede ser útil para algunos: como dijo @SWeko, gracias a la covarianza y la contravarianza,
List<X>
no se puede incorporarList<Y>
, peroList<X>
se puede convertir enIEnumerable<Y>
, , e incluso con conversión implícita.Ejemplo:
pero
La gran ventaja es que no crea una nueva lista en la memoria.
fuente
fuente