Список ковариации приводит к дублированию кода - PullRequest
1 голос
/ 24 октября 2011

У меня есть 2 независимых класса A и B, и у меня есть класс Storage, который управляет хранением объектов типа A и B.

Я пытаюсь абстрагировать код, который делает Store of A и B, однако я застрял из-за ковариации Списка, я не мог назначить List<object> objList = new List<A>(); в следующем коде.

 [DataContract]
public class A {
    public int UID;
}

[DataContract]
public class B {
    public int UID;
}

public class Storage {

    public void Store(A a) {
        List<A> aList = ReadA();
        if (aList == null) {
            aList = new List<A>();
        }
        aList.Add(a);
        WriteNodes(aList);
    }

    public void StoreB(B b) {
        List<B> bList = ReadB();
        if (bList == null) {
            bList = new List<B>();
        }
        bList.Add(b);
        WriteNodes(bList);
    }

    public List<A> ReadA() {
        //deserializes from aFileName and returns List<A>
    }

    public List<B> ReadB() {
        //deserializes from bFileName adn returns List<B>
    }

    private static void WriteNodes<T>(List<T> nodeList) {
        FileStream fs = new FileStream(aFileName, FileMode.Create);
        XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs);
        DataContractSerializer ser =
            new DataContractSerializer(typeof(List<T>));
        ser.WriteObject(writer, nodeList);
        writer.Close();
        fs.Close();
    }
}

Если вы посмотрите на методы StoreA и StoreB, они имеют общий шаблон, за исключением используемого типа. ReadA и ReadB не проблема, я мог бы просто взять тип в качестве другого параметра и создать одну функцию Read.

Так можно ли создать абстракцию для Store, чтобы я не заканчивал методами StoreA и StoreB?

Ответы [ 2 ]

2 голосов
/ 24 октября 2011

А как же:

public void Store<T>(T a) {
        List<T> aList = Read<T>();
        if (aList == null) {
            aList = new List<T>();
        }
        aList.Add(a);
        WriteNodes(aList);
    }

public List<T> Read<T>() {
 //Read a or b depend on T
}
1 голос
/ 24 октября 2011

Да, вы можете сделать это, введя общий интерфейс для элементов, подлежащих сортировке, и извлекая тип элемента в enum.

ХРАНЕНИЕ

public class Storage 
{       
   public Storage()
   {
     // create it once on construction stage
     // so you do not need to check for null each time in Sore()/Read()
     this.AllItems = new List<IItem>();
   }

   public IList<IItem> AllItems { get; private set; }

   public void Store<TItem>(TItem item)  
      where TItem: IItem
   {          
       this.AllItems.Add(item);
   }

   public IEnumerable<IItem> Read(StorageItemType itemType)
   {
      return this.AllItems.Where(item => item.ItemType == itemType);
   }
}

Абстрактный тип хранилища (более общее решение):

// Item types
enum StorageItemType
{
  A,
  B
}

interface IItem
{
   int UID { get; }
   StorageItemType ItemType { get; }
}

public abstract class StorageItemBase: IItem
{
  public int UID { get; private set; }

  public abstract StorageItemType ItemType 
}

public sealed class B : StorageItemBase    
{
  public override StorageItemType ItemType 
  { 
    get 
    {
       return StorageItemType.B; // !!!
    }
  }
}
...