2

假设我有一个 C# 类:

public class Node
{
    public double A { get; set; }
    public double B { get; set; }
}

...以及另一个包含该类型对象列表的类:

public Buffer
{
    private List<Node> _nodes;
    ...
}

现在,假设我需要计算 _nodes 列表中 Node 对象的 A 值的总和。然后(单独)计算 B 的总和。有没有办法使用“通用”Sum() 方法来做到这一点,而不必复制代码?

例如,一种方法可能是:

public class Buffer
{
    ...

    private double SumA()
    {
        double sum;

        foreach (Node node in _nodes)
        {
            sum += node.A;
        }

        return sum;
    }

    private double SumB()
    {
        double sum;

        foreach (Node node in _nodes)
        {
            sum += node.B;
        }

        return sum;
    }
}

这里的问题是 SumA() 和 SumB() 实现的基本算法是相同的,但在上述情况下是重复的。如果 Node 具有更多需要求和的属性,或者 Sum() 是一个更复杂的过程(在我目前正在重构的情况下,这两者都是正确的),则情况会更加复杂。

所以用另一种方式提出这个问题,有没有一种方法可以让我拥有一个 Sum() 方法,但让它对列表中需要求和的类 Node 的任何成员进行操作?

4

5 回答 5

8

您应该从 LINQ 中寻找灵感,也应该寻求实现,使用委托来表示 aNode到 a的投影double。例如,您可以编写:

private double SumB(Func<Node, double> selector)
{
    return _nodes.Sum(selector);
}

然后将其用作:

double sumA = Sum(node => node.A);

或者,如果您仅在内部使用它(您的方法当前是私有的),则根本不要使用该方法:

double sumA = _nodes.Sum(node => node.A);

如果您需要类外的调用者能够做到这一点,您可以Sum公开您的内容,或者如果您已经_nodes以某种方式公开(例如作为IEnumerable<Node>),那么外部代码可以使用:

double sumA = buffer.Nodes.Sum(node => node.A);
于 2013-05-16T13:23:51.467 回答
7

您可以使用委托来获取实际属性进行总结。

private double Sum(Func<Node, double> selector)
{
    double sum = 0;

    foreach (Node node in _nodes)
    {
        sum += selector(node);
    }

    return sum;
}

你可以这样称呼它:

var sumOfA = Sum(x => x.A);
var sumOfB = Sum(x => x.B);

这是一个通用答案,适用于每种算法。

但是,如果您真的只想对这些值求和,则可以使用 LINQ:

var sumOfA = _nodes.Sum(x => x.A);
var sumOfB = _nodes.Sum(x => x.B);

这将消除对您自己的Sum方法的需要。

于 2013-05-16T13:22:58.387 回答
1

使用 LINQ,您可以将总和简化到重复很少的程度:

double sumA = _nodes.Sum(node => node.A);
double sumB = _nodes.Sum(node => node.B);

如果你想隐藏 _nodes 但公开一个 sum 方法,你可以这样做:

private double Sum(Func<Node, double> selector)
{
    return _nodes.Sum(selector);
}
于 2013-05-16T13:25:46.177 回答
1

PropertyInfo就像对成员的引用(在这种情况下是属性):

PropertyInfo info = typeof(Node).GetProperty("A");
double sum = 0;
foreach (Node node in _nodes) sum += (double)info.GetValue(node, null);

并添加:

using System.Reflection;
于 2013-05-16T13:41:19.307 回答
0

您可能还可以为任何 List 类型创建扩展方法

public class Buffer
{
    private List<Node> _nodes;
    private List<double> numsA;

    void MyMethod()
    {
        List<double> numsA = new List<double>();
        List<double> numsB = new List<double>();

        foreach (Node node in _nodes)
        {
            numsA.Add(node.A);
            numsB.Add(node.B);
        }
        double sumA = numsA.Sum();
        double sumB = numsB.Sum();
    }
}

public static class MyExtensions
{
    public static double Sum(this List<double> nodes)
    {
        double sum = 0;
        foreach (double node in nodes)
        {
            sum += node;
        }
        return sum;
    }
} 
于 2013-05-16T13:37:29.240 回答