Использование базовых объектов в качестве параметров в универсальной функции - PullRequest
1 голос
/ 11 сентября 2009

Я пытаюсь реализовать вспомогательный метод с использованием обобщений (C # / 3.5) У меня хорошая структура классов, с базовыми классами, такими как:

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

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

public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{

}

И я хочу получить коллекцию, используя общий метод, например, так:

    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;          
     }
   }

Это не строит, с

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>'.

Объект SomeNiceObjectCollection является коллекцией CollectionBase, а точнее CollectionBase. Так как я могу заставить это работать?

Ответы [ 2 ]

2 голосов
/ 11 сентября 2009

C # не поддерживает приведение между типами списков (ковариация).

Лучшим вариантом для поддержки этого шаблона будет введение интерфейса для метода ReadAllFromDatabase, чтобы вы не полагались на общую коллекцию:

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;          
 }
}
2 голосов
/ 11 сентября 2009

В C # 3.0 это невозможно, но в C # и .NET 4.0 с ковариацией и контравариантностью это возможно.

Подумайте об этом: вы берете коллекцию, содержащую производный объект, и пытаетесь временно обработать ее как коллекцию базового объекта. Если бы это было разрешено, вы можете вставить в список базовые объекты, которые не относятся к производному объекту.

Вот пример:

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!
...