Pregunta

Estoy tratando de implementar un método auxiliar utilizando genéricos (C # / 3.5) Tengo una buena estructura de clases, con clases básicas como las siguientes:

public class SomeNiceObject : ObjectBase
{
  public string Field1{ get; set; }
}

public class CollectionBase<ObjectBase>()
{
  public bool ReadAllFromDatabase();
}

public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{

}

Y deseo recuperar la colección utilizando un método genérico como el siguiente:

    public class DAL
    {

     public SomeNiceObjectCollection Read()
     {
      return ReadFromDB<SomeNiceObjectCollection>();
     }

     T ReadFromDB<T>() where T : CollectionBase<ObjectBase>, new()
     {
      T col = new T();
      col.ReadAllFromDatabase();
      return col;          
     }
   }

Esto no se construye, con

Error   66  The type 'SomeNiceObjectCollection' cannot be used as type parameter 'T' in the generic type or method 'ReadFromDB<T>'.   There is no implicit reference conversion from 'SomeNiceObjectCollection' to 'CollectionBase<ObjectBase>'.

El objeto SomeNiceObjectCollection ES una CollectionBase, una CollectionBase para ser exactos. Entonces, ¿cómo puedo hacer que esto funcione?

¿Fue útil?

Solución

C # no admite la conversión entre tipos de lista (covarianza).

Su mejor apuesta para admitir este patrón sería introducir una interfaz para el método ReadAllFromDatabase para que no se confíe en una colección genérica:

public class SomeNiceObject : ObjectBase
{
  public string Field1{ get; set; }
}

public interface IFromDatabase
{
  bool ReadAllFromDatabase();
}

public class CollectionBase<ObjectBase>() : IFromDatabase
{
  public bool ReadAllFromDatabase();
}

public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{

}

public class DAL
{

 public SomeNiceObjectCollection Read()
 {
  return ReadFromDB<SomeNiceObjectCollection>();
 }

 T ReadFromDB<T>() where T : IFromDatabase, new()
 {
  T col = new T();
  col.ReadAllFromDatabase();
  return col;          
 }
}

Otros consejos

En C # 3.0 esto no es posible, pero con C # y .NET 4.0 con covarianza y contravarianza, esto podría ser posible.

Piénsalo, estás tomando una colección que contiene un objeto derivado y tratas de tratarlo temporalmente como una colección del objeto base. Si esto estuviera permitido, podría insertar objetos base en la lista, lo que no sería del objeto derivado.

Aquí, un ejemplo:

List<String> l = new List<String>();
List<Object> o = l;
l.Add(10); // 10 will be boxed to an Object, but it is not a String!
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top