2012-01-19 18 views
41

¿Cómo puedo lanzar un List<object> al List<SomethingElse>?Cómo agregar la lista <object> a la lista <SomethingElse>

(donde SomethingElse se sabe descender de object)


Bono Chatter

Lanzamiento de la lista:

List<Object> first = ...; 

List<SomethingElse> second = (List<SomethingElse>)first; 

no funciona:

No se puede convertir el tipo 'System.Collections.Generic.List' a 'System.Collections.Generic.List'

Lanzamiento de la lista:

List<SomethingElse> second = first.Cast<SomethingElse>(); 

no funciona:

no se puede convertir implícitamente el tipo 'System.Collections.Generic.List' a 'System.Collections.Generic.List'

i en realidad no necesita la List<T> objetos completo, sólo una ICollection<T> hará:

ICollection<SomethingElse> second = first; 
ICollection<SomethingElse> second = (ICollection<SomethingElse>)first; 
ICollection<SomethingElse> second = first.Cast<SomethingElse>(); 

no funcionan.

+0

¿Te fue útil? http://stackoverflow.com/questions/1266014/c-sharp-casting-a-listobjbase-as-listobj – eldarerathis

+0

Posible duplicado de http://stackoverflow.com/questions/7955890/how-to-cast-listclassb-to -listclassa-when-classb-inherits-from-classa – dash

+0

¿Funcionaría? Lista second = first.Select (o => (SomethingElse) o) .ToList(); – asmo

Respuesta

31

LINQ, tal como se aplica a través de los métodos de extensión dentro de la clase Enumerable, se basa en ejecución diferida:

métodos que se utilizan en una consulta que devuelve una secuencia de valores no consumen los datos de destino hasta que la consulta el objeto está enumerado. Esto se conoce como ejecución diferida.

Cast<T> no crea una nueva lista inmediatamente, sino que almacena toda la información necesaria para realizar la acción. La lista solo se enumerará cuando sea necesario (por ejemplo, a través de una declaración foreach).

En su caso, si lo único que va a iterar sobre la secuencia, se debe considerar que se pega a la interfaz IEnumerable<T>, que es el tipo de retorno declarado de Cast<T>:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>(); 
foreach (SomethingElse se in second) 
{ 
    // ... 
} 

Esta es eficiente, ya que sólo realiza el reparto ya que cada elemento se itera.

Si usted está convencido de que desea una nueva lista que se crea inmediatamente, utilice ToList:

List<SomethingElse> second = first.Cast<SomethingElse>().ToList(); 

Editar: Respondiendo a punto publicado en el comentario:

Depende de lo que entiendas por "una lista que se puede modificar". Hay varios operadores de consulta LINQ que le permitirán modificar aún más la definición de su consulta. Por ejemplo, si desea eliminar todos los SomethingElse elementos cuya IsDeleted propiedad es true, se puede utilizar el Where operador:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>(); 
second = second.Where(element => !element.IsDeleted); 

Si desea agregar una secuencia de nuevos elementos, se puede utilizar el operador Concat:

second = second.Concat(anotherCollectionOfSomethingElse); 

Si desea ordenar la secuencia en orden ascendente de ID, utilice el operador OrderBy:

second = second.OrderBy(element => element.ID); 

Cada vez, estamos aplicando un operador de consulta sobre la anterior definición de nuestra consulta, y asignando la nueva consulta (compuesta) a nuestra variable second. LINQ almacenaría todos sus operadores en la definición de consulta. Luego, cuando la secuencia se enumera realmente (por ejemplo, a través de foreach o ToList), le daría el resultado compuesto de su secuencia, con todos los operadores de consulta aplicados en orden.

Como en todos los casos de ejecución diferida/evaluación diferida, tenga cuidado de no excederse con esto. Si, por ejemplo, va a aplicar un operador Where que reducirá drásticamente el tamaño de su secuencia, podría tener sentido ejecutar la consulta con entusiasmo y almacenar la lista enumerada.

+0

No necesito una nueva lista para crear inmediatamente; pero sí necesito una lista que pueda ser modificada, y no esté limitada por el problema de covarianza. Si 'ToList' es lo que necesito para obtener lo que necesito, necesito usarlo. Preferiría, por supuesto, que la 'Lista' devuelta fuera una envoltura alrededor del' primero', permitiendo también la ejecución diferida. –

13

Creo que estás cerca con la expresión Cast<T>. La diferencia es que Cast<T> devuelve un IEnumerable<T>, no un List<T>.

Prueba esto:

IEnumerable<SomethingElse> second = first.Cast<SomethingElse>(); 

Usted puede obtener una lista al hacer algo similar:

List<SomethingElse> second = first.Cast<SomethingElse>().ToList(); 
9

Usted tiene la opción de utilizar Cast o OfType. Cast lanzará una excepción si no puede convertir al tipo especificado. OfType, por el contrario, devolverá solo los elementos de la lista que se pueden convertir al tipo especificado. Yo recomendaría usar OfType en su situación.

List<Foo> fooList = myList.OfType<Foo>().ToList(); 
Cuestiones relacionadas