Как достичь определенного уровня полиморфизма в C #? - PullRequest
1 голос
/ 02 марта 2011

Это упрощенная версия проблемы, которую я недавно пытался решить.У меня есть следующие два класса:

class Container { }  

class Container<T> : Container  
{  

    T Value  
    {  
        get;  
        private set;  
    }

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

    public T GetValue()
    {
        return Value;
    }
}

Теперь я хочу сделать:

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()); 
} 

Каков наилучший способ реализовать эту функцию?Это вообще возможно?Думаю, у меня есть решение этой проблемы, но я считаю, что это обходной путь, и я ищу какой-то шаблон проектирования.

Заранее благодарю за ваши ответы, Михал.

PS

Я пробовал с интерфейсами, виртуальными функциями, абстрактными классами, абстрактными функциями;даже создание функций в суперклассе, которые будут вызывать свойства реального типа по имени (используя отражение) ... Я до сих пор не могу достичь того, чего хочу ...

Ответы [ 3 ]

6 голосов
/ 02 марта 2011

Вы можете добавить базовый класс Container в интерфейс:

interface IContainer
{
    object GetValue();
}

, который затем явно реализуется в производных классах:

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();
    }
}

Измените список, чтобы он содержал элементы IContainer:

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());
}

Публичное свойство Value в контейнере несколько сбивает с толку, но вы меня поняли.

5 голосов
/ 02 марта 2011

Это то, что вы ищете?Это позволяет вам перебирать значения.

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: Вы можете вызывать Container.RawValue как хотите, это было первое, что пришло на ум.Вот как бы вы назвали это:

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); 
} 
3 голосов
/ 02 марта 2011

Просто добавьте к ответам, которые у вас уже есть, это не вопрос полиморфизма, это проблема специализации типов.Что касается компилятора, Container и Container<T> - это не одно и то же, поэтому List<Container>() - это не то же самое, что List<Container<T>>().

. Вы можете сделать что-то вроде

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

Но с List<Container<double>> это тоже не сработает.Поэтому ответ состоит в том, чтобы переместить определение GetValue() в интерфейс.

...