通用接口和多态

时间:2012-01-16 08:51:11

标签: c# generics architecture interface

我有以下代码:

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 个答案:

答案 0 :(得分:7)

为此,您需要具有非通用接口(通常除了通用接口之外),即非通用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()}
        };
    }
}

答案 1 :(得分:2)

如果我理解正确,您正在尝试存储泛型类型的集合,其中泛型类型参数可能会有所不同。如果是这种情况,则无法直接进行,如下例所示:

// 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);