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
Xrealmente 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>)ListOfXno 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
Mammalen 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
ConvertAllmé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 seXderiva deY), esto se debe a queList<T>se define como:(Tenga en cuenta que en esta declaración, escriba
Taquí 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
Giraffederive deAnimal:Esto se debe a que
IEnumerable<T>admite la covarianzaT: esto tiene sentido dado queIEnumerableimplica que la colección no se puede cambiar, ya que no admite métodos para Agregar o quitar elementos de la colección. Tengaouten 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
Listno 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 resultadoInvalidCastExceptionsi no es posible lanzar uno o más elementos (lo que sería el mismo comportamiento que hacer lo explícito). emitido en elforeachbucle del OP ).Filtrado y Fundición con
OfType<T>()Si la lista de entrada contiene elementos de tipos diferentes e incompatibles,
InvalidCastExceptionse 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 yen elforeach)que también se intentará el casting. Sin embargo, si no es posible lanzar, se
InvalidCastExceptionobtendrá 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
foreachno 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