универсальные интерфейсы и полиморфизм - PullRequest
7 голосов
/ 16 января 2012

У меня есть следующий код:

public abstract class Operand<T>
{
    public T Value { get; protected set; }

    public bool IsEmpty { get; protected set; }

    public override string ToString()
    {
        return IsEmpty ? Value.ToString() : string.Empty;
    }
}
public class DoubleOperand : Operand<Double> {}

public interface IOperandFactory<T>
    {
        Operand<T> CreateEmptyOperand();
        Operand<T> CreateOperand(T value);
    }

public class DoubleFactory: IOperandFactory<double>
{
    public Operand<Double> CreateEmptyOperand()
    {
        //implementation
    }

    public Operand<Double> CreateOperand(double value)
    {
        //implementation
    }
}

Я упростил код, чтобы просто показать структуру. Теперь мне нужен associationDictionary, который будет возвращать IOperandFactory для требуемого Type: Как то так:

var factoryDict = 
new Dictionary<Type, IOperandFactory<>>() { { typeof(double), new DoubleFactory() } };

Не могли бы вы помочь мне добиться этого, если это возможно?

Ответы [ 2 ]

7 голосов
/ 16 января 2012

Для этого вам понадобится неуниверсальный интерфейс (обычно в дополнение к универсальному интерфейсу), т. Е. Неуниверсальный Operand, с Operand<T> : Operand (также может быть интерфейсом) и неуниверсальный IOperandFactory с IOperandFactory<T> : IOperandFactory. Единственный другой вариант - сохранить Dictionary<Type, object> и при необходимости вызвать вызывающего.

Вот неуниверсальный подход:

using System.Collections.Generic;
using System;
public interface IOperand
{
    object Value { get; }
    bool IsEmpty { get; }
}
public abstract class Operand<T> : IOperand
{
    public T Value { get; protected set; }
    object IOperand.Value { get { return Value; } }
    public bool IsEmpty { get; protected set; }
    public override string ToString()
    {
        return IsEmpty ? Value.ToString() : string.Empty;
    }
}
public class DoubleOperand : Operand<double> { }

public interface IOperandFactory
{
    IOperand CreateEmptyOperand();
    IOperand CreateOperand(object value);
}
public interface IOperandFactory<T> : IOperandFactory
{
    new Operand<T> CreateEmptyOperand();
    Operand<T> CreateOperand(T value);
}

public class DoubleFactory : IOperandFactory<double>
{
    public Operand<double> CreateEmptyOperand()
    {
        throw new NotImplementedException();
    }
    IOperand IOperandFactory.CreateEmptyOperand() {
        return CreateEmptyOperand();
    }

    IOperand IOperandFactory.CreateOperand(object value) {
        return CreateOperand((double)value);
    }
    public Operand<double> CreateOperand(double value)
    {
        throw new NotImplementedException();
    }
}

static class Program
{
    static void Main()
    {
        var factoryDict = new Dictionary<Type, IOperandFactory> {
          {typeof (double), new DoubleFactory()}
        };
    }
}
2 голосов
/ 16 января 2012

Если я правильно понимаю, вы пытаетесь сохранить коллекцию универсальных типов, где параметры универсальных типов могут различаться.Если это так, то это невозможно сделать напрямую, как показывает следующий пример:

// You have lists of different types:
List<double> doubleCollection = new List<double>();
List<string> stringCollection = new List<string>();

// Now to store generically:
var collection = new List<List< /* ... Which type parameter to use? ... */ >>();

Что здесь должно быть очевидно, так это то, что невозможно определить, какой параметр типа использовать.Вместо этого (что касается вашего примера), вы можете захотеть что-то вроде этого:

public interface IOperand
{
}

public interface IOperand<T>
{
}

public interface IOperandFactory
{
    IOperand CreateEmptyOperand();
    IOperand CreateOperand(object value);
}

public interface IOperandFactory<T> : IOperandFactory
{
    new IOperand<T> CreateEmptyOperand();
    IOperand<T> CreateOperand(T value);
}

public class DoubleFactory : IOperandFactory<double>
{
    public IOperand<double> CreateEmptyOperand()
    {
        throw new NotImplementedException();
    }

    public IOperand<double> CreateOperand(double value)
    {
        throw new NotImplementedException();
    }

    IOperand IOperandFactory.CreateEmptyOperand()
    {
        throw new NotImplementedException();
    }

    public IOperand CreateOperand(object value)
    {
        throw new NotImplementedException();
    }
}

public class SomeContainer
{
    public SomeContainer()
    {
        var factoryDict = new Dictionary<Type, IOperandFactory>()
        {
            { typeof(double), (IOperandFactory)new DoubleFactory() }
        };
    }
}

Это может быть не самое элегантное решение, но оно позволит вам хранить разные универсальные типы в одной коллекции.,Проблема с этим, однако, заключается в том, что вызывающая сторона, получающая доступ к такой коллекции, должна знать, к какому типу приводиться.Например:

// ... Inside SomeContainer ...
public IOperandFactory<T> GetFactory<T>()
{
    return (IOperandFactory<T>)factoryDict[typeof(T)];
}

Таким образом, вы можете получить DoubleFactory используя:

IOperandFactory<double> doubleFactory = mSomeContainerInstance.GetFactory<double>();
IOperand<double> emptyOperand = doubleFactory.CreateEmptyOperand();
IOperand<double> filledOperand = doubleFactory.CreateOperand(1.0d);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...