如何使用泛型编写通用操纵器?

时间:2017-01-03 17:49:48

标签: c# generics interface

我有定义值和少量操作的界面:

public interface IValue<T>
{
    T Value { get; }

    void InteractionA(IValue<T> target);
    void InteractionB(IValue<T> target);
    bool Check(IValue<T> target);
}

然后我基于该接口实现类

public class DoubleValue : IValue<double>
{
    public double Value { get; private set; }

    public bool Check(IValue<double> target)
    {
        // ...
        return false;
    }

    public void InteractionA(IValue<double> target)
    {
        // ...
    }

    public void InteractionB(IValue<double> target)
    {
        // ...
    }
}

现在我想制作操作于值池并使用泛型的通用操纵器(所以我只写一次)。由于我将来想要使用这个类的方式,它不能被声明为static。将泛型类型移动到方法中也没有任何好处。 我能得到的最接近的是:

public class ValueManipulator<T>
{
    public IEnumerable<IValue<T>> Pool { get; private set; }

    public ValueManipulator(IEnumerable<IValue<T>> pool)
    {
        Pool = pool;
    }

    public void ManipulateA()
    {
        foreach (int i in Enumerable.Range(0, Pool.Count()))
        {
            IValue<T> firstValue = Pool.ElementAt(i);

            foreach (IValue<T> secondValue in Pool.Skip(i))
            {
                if (firstValue.Check(secondValue))
                    firstValue.InteractionA(secondValue);

                else
                    firstValue.InteractionB(secondValue);
            }
        }
    }

    public void ManipulateB()
    {
        // ...
    }
}

这个ValueManipulator类的主要问题是我需要知道DoubleValue中使用的IV的IV(在本例中为double)。所以它看起来像这样:

static void Main(string[] args)
{
    ValueManipulator<double> doubleManipulator = new ValueManipulator<double>();
    doubleManipulator.Manipulate(ProvideDoubles());
}

private static IEnumerable<DoubleValue> ProvideDoubles()
{
    yield return new DoubleValue();
    yield return new DoubleValue();
    yield return new DoubleValue();
}

如何创建ValueManipulator,以便用户不需要知道值实现中使用的是什么类型?

1 个答案:

答案 0 :(得分:2)

好吧,如果您的ValueManipulator<T>没有状态,根据您的代码片段似乎是您的情况,那么只需将方法设为通用而不是类,这样就可以利用类型推断。

public class ValueManipulator
{
    public void Manipulate<T>(IEnumerable<IValue<T>> pool)
    {
        foreach (int i in Enumerable.Range(0, pool.Count()))
        {
            IValue<T> firstValue = pool.ElementAt(i);

            foreach (IValue<T> secondValue in pool.Skip(i))
            {
                if (firstValue.Check(secondValue))
                    firstValue.InteractionA(secondValue);

                else
                    firstValue.InteractionB(secondValue);
            }
        }
    }
}

现在你可以做到:

ValueManipulator myManipulator = new ValueManipulator();
myManipulator.Manipulate(ProvideDoubles()); //type inference will figure out T is double

如果这是一个有效的解决方案,那么考虑将ValueManipulator作为静态类:

ValueManipulator.Manipulate(ProvideDoubles());

Pd积。请按照评论中的建议进行操作,并将ValueType更改为其他一些不那么令人困惑的名称。

更新在对您的问题进行最新编辑后,您明确指出ValueManipulator<T> 具有状态,解决方案似乎正在实施静态工厂类:

public static class ValueManipulator
{
     public static ValueManipulator<T> Create<T>(IEnumerable<IValue<T>> pool)
         => new ValueManipulator<T>(pool);
}

public class ValueManipulator<T> { ... }

再次让类型推断完成它的工作:

var doubleManipulator = ValueManipulator.Create(ProvideDoubles());