tags:

views:

190

answers:

2

I am having some trouble with an idea that at its simplest seems like it should work.

I am trying to overload a Property of Type BindingList<T> in a subclass with a BindingList of <subclasss T>. There are ways I can get around this but it seems the 'nicest' way would be without any direct casting. I have tried a bunch of options and have some solutions but I am not particularly happy with any of them.

Is there a best approach to this? A simple code example might be the best descriptor In this example below, I want to derive a fruitbowl to contain only apples but use the same property name to access this BindingList<> of Apples (in the case of the subclass; generic fruit in the case of the Super class).

--------Example-------

class Fruit{}
class Apple: Fruit {}

class FruitBowl
{
  protected BindingList<Fruit>  m_aFruits;

  public BindingList<Fruit> Fruits
  {
    get {return m_aFruits;}
  }
}

class AppleBowl : FruitBowl
{
  public BindingList<Apple> Fruits
  {
    get {return m_aFruits;}
  }
}
+1  A: 
class FruitBowl<T> where T : Fruit //this requires T to inherit from Fruit
{
    protected BindingList<T> Fruits;
}

class AppleBowl : FruitBowl<Apple>
{
    //AppleBowl will have an inherited property Fruits 
    //of type BindingList<Apple>
}
Rex M
+1 - Also, whack a "where T : Fruit" constraint on your FruitBowl<T> for even more type safety.
Matt Hamilton
@Matt was typing it as you added the comment :)
Rex M
+2  A: 

What you're attempting to do is known as Co/Contra Variance. Unfortunately this is not supported on concrete types in C# (available on interfaces only for C# 4.0). Given the implementation of BindingList<T> it is not possible to do what you want and maintain only a single list.

You can attempt to fake this in several ways. One way to get around this is to only use IEnumerable<T> on the sub class. In this case a simple LINQ query will do the trick.

class AppleBowl : FruitBowl
{
  public IEnumerableApple> TypedFruits
  {
    get {return base.Fruits.Cast<Apple>();}
  }
}
JaredPar
His example is a little ambiguous, but I don't think he is necessarily meaning to attempt co/contravariance here. He stated that he does want AppleBowl *instance* to hold only apples, so there doesn't have to be a type change involved.
Rex M
@Rex it may not be exactly what he's looking for but in order to achieve his goals it's what he'll need. There has to be a type change involved if he wants to return the same concrete class with 2 different generic arguments
JaredPar