14
public abstract Column<T>
{
   private T Value {get;set;}    

   public abstract string Format();

}

public class DateColumn : Column<DateTime>
{
   public override string Format()
   {
      return Value.ToString("dd-MMM-yyyy");
   }
}

public class NumberColumn : Column<decimal>
{
   public override string Format()
   {
      return Value.ToString();
   }
}

The problem I have is adding these into a generic collection. I know its possible but how can I store multiple types in a collection etc

IList<Column<?>> columns = new List<Column<?>()

I would really appreciate any advice on achieving this goal. The goal being having different column types stored in the same List. Its worth mentioning I am using NHibernate and the discriminator to load the appropriate object.Ultimately the Value needs to have the type of the class.

Many thanks for your help in advance.

Jonathan
  • 2,318
  • 7
  • 25
  • 44
  • I am confused about the point of this. Generics helps with type safety. Regardlesss, if you really wanted to do this, couldn't you populate your list with Column? – Killnine May 15 '12 at 18:48
  • No that wouldnt work, I have tried using a Column I think the problem really lies with having Value defined through polymorphism and then being able to store that in a collection. I use the discriminator to load the different column types. – Jonathan May 15 '12 at 18:49
  • There are [a few](http://stackoverflow.com/q/3215402/590790) [duplicates](http://stackoverflow.com/q/3777057/590790) of this question already. In addition to the 'base-type' solution [posted here by JaredPar](http://stackoverflow.com/a/10606974/590790), I would like to propose [following the adapter pattern to create a non-generic wrapper to this purpose](http://stackoverflow.com/a/34417767/590790), so that the Liskov Substitution Principle is not broken. – Steven Jeuris Dec 25 '15 at 15:29

3 Answers3

23

In order to be stored in a List<T> together the columns must have a common base type. The closest common base class of DateColumn and NumberColumn is object. Neither derives from Column<T> but instead a specific and different instantiation of Column<T>.

One solution here is to introduce a non-generic Column type which Column<T> derives from and store that in the List

public abstract class Column { 
  public abstract object ValueUntyped { get; }
}

public abstract class Column<T> : Column {
  public T Value { get; set; }
  public override object ValueUntyped { get { return Value; } }
}

...

IList<Column> list = new List<Column>();
list.Add(new DateColumn());
list.Add(new NumberColumn());
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
3

Generics are all about specifying type. If you want to use dynamic types, use classic ArrayList instead.

Pol
  • 5,064
  • 4
  • 32
  • 51
  • 2
    In this case I don't believe the OP wants dynamic typing but instead wants to take advantage of base types and polymorphic behavior – JaredPar May 15 '12 at 18:55
  • Yes you're correct @JaredPar I need to Parse the values and trying to guess what an object is is extremely difficult. – Jonathan May 15 '12 at 18:57
  • 2
    You're right, I +1ed your detailed answer. – Pol May 15 '12 at 18:57
3

It probably makes sense to derive from a non-generic Column class that wraps up as much of the non-generic common interface of a column... then to declare your list as List<Column>.

spender
  • 117,338
  • 33
  • 229
  • 351