How to achieve some level of polymorphism in C#?

336 Views Asked by At

This is a simplified version of the problem that I've been trying to solve recently. I have the following two classes:

class Container { }  

class Container<T> : Container  
{  

    T Value  
    {  
        get;  
        private set;  
    }

    public Container(T value)  
    {  
        Value = value;  
    }  

    public T GetValue()
    {
        return Value;
    }
}

Now I want to do:

Container<int> c1 = new Container<int>(10);
Container<double> c2 = new Container<double>(5.5);

List<Container> list = new List<Container>();
list.Add(c1);  
list.Add(c2);  

foreach (Container item in list)
{  
    Console.WriteLine(item.Value);
    Console.WriteLine(item.GetValue()); 
} 

What is the best way to implement this functionality? Is it possible at all? I think I might have on solution to this issue, but I consider it a work-around and I am looking for some design pattern.

Thank you in advance for your responses, Michal.

P.S.

I tried with interfaces, virtual functions, abstract classes, abstract functions; even creating functions in a superclass that would call the properties of the real type by name (using reflection)...I am still not able to achieve what I want...

3

There are 3 best solutions below

1
On

You could the base class Container into an interface:

interface IContainer
{
    object GetValue();
}

Which is then explicitly implemented in the derived classes:

class Container<T> : IContainer
{
    public T Value { get; private set; }

    public Container(T value)
    {
        Value = value;
    }

    public T GetValue()
    {
        return Value; 
    }

    object IContainer.GetValue()
    {
        return this.GetValue();
    }
}

Change the list to contain IContainer elements:

Container<int> c1 = new Container<int>(10);
Container<double> c2 = new Container<double>(5.5);
List<IContainer> list = new List<IContainer>();
list.Add(c1);
list.Add(c2);

foreach (IContainer item in list)
{
    Console.WriteLine(item.GetValue());
}

The public Value property on Container is kind of confusing, but you get my point.

0
On

Is something like this what you're looking for? This allows you to iterate through the values.

abstract class Container
{
    public abstract object RawValue { get; }
}

class Container<T> : Container
{
    public override object RawValue
    {
        get { return this.Value; }
    }

    T Value
    {
        get;
        private set;
    }

    public Container(T value)
    {
        Value = value;
    }
}

EDIT: You can call Container.RawValue whatever you want, that was the first thing that came to mind. Here is how you would call it:

Container<int> c1 = new Container<int>(10);
Container<double> c2 = new Container<double>(5.5);

List<Container> list = new List<Container>();
list.Add(c1);  
list.Add(c2);  

foreach (Container item in list)
{  
    Console.WriteLine(item.RawValue);
    Console.WriteLine(item.RawValue); 
} 
0
On

Just to add to the answers you already have, this isn't a matter of polymorphism, it's a problem of type specialization. As far as the compiler is concerned, Container and Container<T> are not the same thing, so List<Container>() is not the same thing as List<Container<T>>().

You can do something like

List<Container<int>> list = new List<Container<int>>();

But that won't work with List<Container<double>> either. So the answer is to move the GetValue() definition to an interface.