remarks generate example c# generics inheritance list casting

generate - params comments c#



C#emitir una lista<ObjBase> como lista<Obj> (11)

¿Por qué no puedo lanzar una List<ObjBase> como List<Obj> ? ¿Por qué no funciona lo siguiente:

internal class ObjBase { } internal class Obj : ObjBase { } internal class ObjManager { internal List<Obj> returnStuff() { return getSomeStuff() as List<Obj>; } private List<ObjBase> getSomeStuff() { return new List<ObjBase>(); } }

En su lugar tengo que hacer esto:

internal class ObjBase { } internal class Obj : ObjBase { } internal class ObjManager { internal List<Obj> returnStuff() { List<ObjBase> returnedList = getSomeStuff(); List<Obj> listToReturn = new List<Obj>(returnedList.Count); foreach (ObjBase currentBaseObject in returnedList) { listToReturn.Add(currentBaseObject as Obj); } return listToReturn; } private List<ObjBase> getSomeStuff() { return new List<ObjBase>(); } }

Recibo el siguiente error en Visual Studio 2008 (acortado para facilitar la lectura):

No se puede convertir el tipo ''Lista'' en ''Lista'' a través de una conversión de referencia, conversión de boxeo, conversión de unboxing, conversión de ajuste o conversión de tipo nulo

Gracias.



Pensé que el compilador se daría cuenta de que quería que se realizaran acciones en los objetos de la lista y no que estuviera intentando realizar la propia lista.

Más información:

public abstract class ObjBase { } internal interface IDatabaseObject { } public class Obj : ObjBase, IDatabaseObject { } internal interface IDatabaseObjectManager { List<ObjBase> getSomeStuff(); } public class ObjManager : IObjManager { public List<Obj> returnStuff() { return getSomeStuff().Cast <Customer>().ToList<Customer>(); } private List<ObjBase> getSomeStuff() { return new List<ObjBase>(); } }

Ahora puede ir el código de cliente fuera de esta DLL: ObjManager objM = new ObjManager (); List listOB = objM.returnStuff (); Voy a crear varios tipos de Obj y ObjManager para esta parte (O / RM) de la aplicación.

(¡El bloque de comentarios Darn se quedó sin caracteres !:-)


Así es como arreglé la conversión de un

list<SomeOtherObject>

a un

object

y luego a un

List<object>

https://.com/a/16147909/2307326


C # actualmente no admite varianza para tipos genéricos. De lo que he leído, esto cambiará en 4.0.

Consulte here para obtener más información sobre la variación en genéricos.



Creo que estás malinterpretando el reparto que estás tratando de hacer. Está pensando que está cambiando el tipo de objeto que se almacena en la lista, donde en realidad está tratando de cambiar el tipo de la lista en sí. Es bastante lógico que no puedas cambiar la lista en sí misma, ya que ya la has rellenado.

Puede verlo como una lista de una clase base y luego emitirlo cuando está procesando los elementos de la lista, ese sería mi enfoque.

¿Cuál es el propósito de este intento de lanzamiento?


Este es un gran dolor en C #: así se diseñaron los genéricos. La lista no se extiende a la lista, es solo un tipo completamente diferente. No puedes lanzarlos o asignarlos entre sí de ninguna manera, tu única opción es copiar una lista a la otra.


Linq tiene un método ConvertAll. así que algo como

list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));

No estoy seguro de qué más sugerir. Supongo que ObjBase es la clase base, y si todos los objetos ObjBase son objetos Obj, no estoy seguro de por qué tendría los dos objetos en primer lugar. Tal vez estoy fuera de la marca.

Edición: el método list.Cast funcionaría mejor que el anterior, suponiendo que se puedan moldear entre sí. Olvidé eso hasta que leí las otras respuestas.



Puede usar los métodos de extensión Cast y ToList de System.Linq para tener esto en una línea.

En lugar de

internal List<Obj> returnStuff() { return getSomeStuff() as List<Obj>; }

hacer esto:

internal List<Obj> returnStuff() { return getSomeStuff().Cast<Obj>().ToList(); }


Solo puedo describir el "problema" desde una vista de Java, pero por lo poco que sé, este aspecto es el mismo tanto en C # como en Java:

Una List<ObjBase> no es una List<Obj> , porque podría contener un objeto ObjBase que no es un objeto Obj .

La otra forma de evitar una List<Obj> no se puede convertir en una List<ObjBase> porque la primera garantiza aceptar una llamada Add() con un argumento ObjBase , que esta última no aceptará.

Así que para resumir: aunque un Obj is-a ObjBase una List<Obj> no es una List<ObjBase> .


list.ConvertAll parece tentador pero tiene una gran desventaja: creará una lista completamente nueva. Esto afectará el rendimiento y el uso de la memoria, especialmente para listas grandes.

Con un poco más de esfuerzo, puede crear una clase de lista de envoltorio que mantenga la lista original como referencia interna y convertir los elementos solo cuando se utilizan.

Uso:

var x = new List<ObjBase>(); var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>

Código para agregar a su biblioteca:

public static class Extensions { public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list) { return new CastedList<TTo, TFrom>(list); } } public class CastedList<TTo, TFrom> : IList<TTo> { public IList<TFrom> BaseList; public CastedList(IList<TFrom> baseList) { BaseList = baseList; } // IEnumerable IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); } // IEnumerable<> public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); } // ICollection public int Count { get { return BaseList.Count; } } public bool IsReadOnly { get { return BaseList.IsReadOnly; } } public void Add(TTo item) { BaseList.Add((TFrom)(object)item); } public void Clear() { BaseList.Clear(); } public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); } public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); } public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); } // IList public TTo this[int index] { get { return (TTo)(object)BaseList[index]; } set { BaseList[index] = (TFrom)(object)value; } } public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); } public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); } public void RemoveAt(int index) { BaseList.RemoveAt(index); } } public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo> { public IEnumerator<TFrom> BaseEnumerator; public CastedEnumerator(IEnumerator<TFrom> baseEnumerator) { BaseEnumerator = baseEnumerator; } // IDisposable public void Dispose() { BaseEnumerator.Dispose(); } // IEnumerator object IEnumerator.Current { get { return BaseEnumerator.Current; } } public bool MoveNext() { return BaseEnumerator.MoveNext(); } public void Reset() { BaseEnumerator.Reset(); } // IEnumerator<> public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } } }