Gerard Sexton
Gerard Sexton

Reputation: 3200

Generics design pattern for holding a list of varying types

I have a Column class:

class Column<T> where T : IComparable, IConvertible
{
    private List<T> _records;
    ...
}

and a table class that should hold many columns of varying datatypes.

class Table
{
    private List<Column> columns;
    ...
}

Obviously this wont compile but I am after a standard design pattern for handling this idea.

Any ideas?

Upvotes: 3

Views: 941

Answers (2)

supercat
supercat

Reputation: 81151

The only circumstance where I can see that it would be useful to do what you describe would be if one wishes to store objects that both derive from a particular class and which implement a particular interface, when the classes one may wish to store (which all do both things) do not share a common base type that does both. For example, there may be a type family consisting of a Foo, a CloneableFoo (which derives from Foo and implements a cloneable interface), a DerivedFoo (which derives from Foo, and does not implement cloning), and a CloneableDerivedFoo (which derives from Foo and implements cloning), and one may wish to have a method which would accept any derivative of Foo that allows cloning. Note that the only common base type of CloneableFoo and CloneableDerivedFoo, both of which should be allowed in the collection, is Foo, which does not allow cloning.

A solution to this general problem is to derive an interface, ISelf<out T>, whose single member, "self", is a read-only property of type T. Any interface IWhatever which might want to be used in conjunction with another interface or base class should declare a generic form IWhatever<out T> which inherits both the non-generic form and also ISelf<T>. Any class implementing any generic interface of that style should then also implement ISelf<ItsOwnClass> in the obvious way (just return itself).

If that is done, one may declare an object which implements any combination of interfaces using nested interfaces that implement ISelf, and may without a typecast use any such object as its proper type (by using the proper number of ".Self" property accessors). Interestingly, one may typecast any class which implements a set of such interfaces to any nested combination of them. For example, an IFoo<IBar<IBoz<WhateverDerived>>> may be typecast to an IBoz<IBar<IFoo<WhateverBase>>>.

Upvotes: 0

LukeH
LukeH

Reputation: 269358

You could use a common, non-generic base class or interface:

// or maybe interface IColumn instead, depending on your needs
class Column
{
    // any non-generic stuff common to all columns
}

class Column<T> : Column where T : IComparable, IConvertible
{
    // any generic stuff specific to Column<T>
}

class Table
{
    private List<Column> _columns;
}

Upvotes: 6

Related Questions