2009-07-25 2 views
1

Это вопрос дизайна. У меня есть бизнес-объект и 5 типов бизнес-объектов, которые получены из него.Решение проблемы отсутствия ковариации с дженериками в C# 2.0 (BindingList)

У меня также будет класс, в котором есть BindingList. У меня будет 5 классов, полученных из него.

Поскольку ковариация здесь не работает, как бы вы структурировали проект, чтобы свести к минимуму повторение кода? Я мог бы, конечно, вытащить BindingList и пойти с DataTable, и в этом случае проблема будет устранена.

Но так как все бредят о BindingList, я бы ЛЮБЛЮ, чтобы увидеть, как вы, ребята, подходите к этому.

РАСТВОР (на основе ответа Павла Минаева):

public class SampleBase 
    { 
     protected string m_seq; 
     protected string m_id; 
     protected string m_weight; 
     protected string m_units;  

     public SampleBase(string seq, string id, string weight, string units) 
     { 
      Seq = seq; 
      Id = id; 
      Weight = weight; 
      Units = units; 
     } 

     public SampleBase() { } 

     public string Seq 
     { 
      get { return m_seq; } 
      set { m_seq = value; } 
     } 

     public string Id 
     { 
      get { return m_id; } 
      set { m_id = value; } 
     } 

     public string Weight 
     { 
      get { return m_weight; } 
      set { m_weight = value; } 
     } 

     public string Units 
     { 
      get { return m_units; } 
      set { m_units = value; } 
     } 

    } 

    public class FwdSample : SampleBase 
    { 
     protected string m_std_id; 

     public FwdSample() { } 

     public FwdSample (string seq, string id, string weight, string units, string std_id) : base(seq, id, weight, units) 
     { 
      StdId = std_id; 
     } 

     public string StdId 
     { 
      get { return m_std_id; } 
      set { m_std_id = value; } 
     } 
    } 
    //End of Sample Classes 





    public abstract class RunBase<T> where T : SampleBase , new() 
    { 
     protected BindingList<T> m_samples; 



     public RunBase() {} 

     public void Add(T sample) 
     { 
      m_samples.Add(sample); 
     } 

     public void Update(int index, T sample) 
     { 
      m_samples[index] = sample; 
     } 

     public void Delete(int index) 
     { 
      m_samples.RemoveAt(index); 
     } 



     public BindingList<T> Samples 
     { 
      get { return m_samples; } 
     } 
    } 


    public class FwdRun : RunBase<FwdSample> 
    { 

     public FwdRun() 
     { 
      m_samples = new BindingList<FwdSample>(); 
     } 


    } 
+0

Если клиенты вашего класса только быть в состоянии получить элементы от 'BindingList', или добавлять новые элементы к нему, а? –

+0

Как добавить, так и получить – sarsnake

+0

Не забудьте отметить ответ, если вы получите удовлетворительный ответ. – kevindaub

ответ

3

Если предположить, что BindingList элемент является частным (или защищенный), и в противном случае не подвергается в своем классе API, вы, вероятно, хотите что-то вроде этого:

class Base 
    { 
     // No BindingList here. All members that don't need it should be here 
     ... 
    } 

    class Base<TDerived> : Base where TDerived : Base<TDerived> 
    { 
     BindingList<TDerived> list = new BindingList<TDerived>(); 

     // All members that need BindingList should be here 
    } 

    class Derived1 : Base<Derived1> { ... } 
    class Derived2 : Base<Derived2> { ... } 
    ... 
+0

не отображается в пользовательском интерфейсе. Я взгляну на это внимательно - мозг слишком жарен. спасибо – sarsnake

+0

Я не имею в виду интерфейс. «Клиенты класса» означают код, который создает и использует объекты класса. –

+0

+1 - Мне любопытно, есть ли какая-то конкретная причина, по которой вы решили разделить Base и Base , где TDerived: Base будет достаточно. – dahlbyk

0

Если у вас есть отношения наследования между детьми, почему бы не использовать BindingList<TheBaseClass> в качестве основного типа коллекции?

Самый яркий пример того, когда вам нужно будет использовать ковариацию, - это когда вы хотите обработать BindingList<TheDerivedClass> как BindingList<TheBaseClass>. Можете ли вы дать нам конкретный пример того, где это сбивает вас с толку? Многие сценарии, для которых совпадение - это опрос, также могут быть решены с помощью комбинации дженериков, ограничений и иногда дополнительных интерфейсов.

+0

попытается объяснить. У меня есть сетка с образцами. Существует 6 типов образцов; каждый тип имеет разные столбцы в сетке (некоторые из них являются общими для нескольких типов). Естественно, я создал объект SampleBase и хотел получить из него 6 типов. Тогда у меня также есть объект Run, который содержит BindingList из SampleBase, так как есть 6 типов запуска (тип образца = тип прогона для простоты). У меня есть 6 объектов, которые получены из RunBase. Возможно, я усложняю это; но я стараюсь иметь хороший дизайн с минимальным повторением кода. Надеюсь, я прояснился. – sarsnake

+0

oh и сетка может отображать только один тип запуска (тип образца) за раз. Так скажите, что в сетке отображается 100 образцов, все они одинаковы. – sarsnake

+0

Из вашего описания это звучит так, как будто вам просто нужно сделать свой класс «Run» универсальным по типу вашего бизнес-объекта. –

1

Этот пример работает только с .net 3.5 или выше. . :(

Возможно, это свойство, которое возвращает все унаследованные объекты У меня был подобный вопрос и с помощью System.Linq Вот что я использовал:.

List<A> testme = new List<B>().OfType<A>().ToList(); 

Или бросить все из них к родителю:

List<A> testme = new List<B>().Cast<A>().ToList(); 

Приведенный выше код был от this answer. Благодаря Matt.

+0

Я только что проверил msdn и, видимо, System.Linq не поддерживается в Compact Framework. – sarsnake

Смежные вопросы