通用接口和多态性

7
我有以下代码:

我有以下代码:

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
    }
}

我简化了代码,只展示结构。 现在我需要一个关联字典,它将返回所需TypeIOperandFactory: 就像这样:

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

如果可能的话,你能帮我实现它吗?

2个回答

7
要实现这个目标,你需要有一个非泛型接口(通常除了泛型接口之外),即一个非泛型的操作数,使用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

如果我理解正确,您正在尝试存储一组通用类型,其中通用类型参数可能会有所不同。 如果是这种情况,则直接存储是不可能的,如下面的示例所示:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接