Solution to the lack of covariance with generics in c# 2.0 (BindingList)
-
19-09-2019 - |
Question
It's a design question. I have a business object, and 5 business object types that are derived from it.
I also will have a class which has BindingList as a member. I will have 5 classes derived from it.
Since covariance doesn't work here, how would you structure the design to minimize code repetition? I could of course chuck the BindingList and go with DataTable in which case the problem is eliminated.
But since everyone raves about BindingList I would LOVE to see how you guys would approach this.
SOLUTION (based on Pavel Minaev's answer):
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>();
}
}
Solution
Assuming your BindingList
member is private (or protected), and isn't otherwise exposed in your class API, you'd probably want something like this:
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> { ... }
...
OTHER TIPS
This example only works with .net 3.5 or higher. :(
Perhaps a property that returns all of the inherited objects. I had a similar question and using System.Linq. Here is what I used:
List<A> testme = new List<B>().OfType<A>().ToList();
Or cast all of them to the parent:
List<A> testme = new List<B>().Cast<A>().ToList();
The above code was from this answer. Thanks Matt.
If you have an inheritance relationship between the children, why not use BindingList<TheBaseClass>
as your main collection type?
The most prominent example of when you would need to use covariance is when you wanted to treat a BindingList<TheDerivedClass>
as BindingList<TheBaseClass>
. Can you give us a specific example of where this is tripping you up? Many of the scenarios for which coviarance is an anaswer can also be solved with a combination of generics, constraints and occasionally additional interfaces.