【问题标题】:How to write universal manipulator using generics?如何使用泛型编写通用操纵器?
【发布时间】:2017-01-03 17:49:47
【问题描述】:

我有定义值和少量操作的接口:

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)
    {
        // ...
    }
}

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

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 中使用的 IValue 的 T(在本例中为 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,这样用户就不需要知道值实现中使用了什么类型?

【问题讨论】:

  • 你可以简化你的循环int i = 1; foreach(var first in pool) { foreach(var second in pool.Skip(i)) {....} i++;}

标签: c# generics interface


【解决方案1】:

好吧,如果您的 ValueManipulator&lt;T&gt; 没有状态(根据您的代码 sn-ps 似乎是您的情况),那么只需将方法设为通用而不是类,这样您就可以利用类型推断。

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

P.D.请遵循评论中的建议,并将ValueType 更改为其他不那么容易混淆的名称。

更新在您对问题进行最新编辑后,明确指出ValueManipulator&lt;T&gt; 确实有状态,解决方案似乎正在实现一个静态工厂类:

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

【讨论】:

  • 你是对的,它看起来像 ValueManipulator 没有状态,但它的当前工作的方法过于简化(并且需要实例)。我会更新我的问题。
  • 这确实是一个解决方案。
猜你喜欢
  • 1970-01-01
  • 2017-12-06
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 2023-01-01
  • 2020-12-31
相关资源
最近更新 更多