Использование базовых объектов в качестве параметров в универсальной функции

StackOverflow https://stackoverflow.com/questions/1410579

  •  05-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь реализовать вспомогательный метод с использованием обобщений (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. Так как я могу заставить это работать?

Это было полезно?

Решение

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

Другие советы

В 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!
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top