【发布时间】:2015-03-22 10:32:34
【问题描述】:
在我的代码库中,我有大量的类需要对其成员执行各种集体操作以获得结果(平均值、标准差、置信区间等)
AverageLINQ Extension方法已经存在,而StandardDeviation不存在,所以我实现如下:
public static double StandardDeviation<T>(this IEnumerable<T> source, Func<T, double> selector)
{
var average = source.Average(selector);
var sumOfSquares = source.Sum(sample => Math.Pow(selector(sample) - average, 2));
return Math.Pow(sumOfSquares, 0.5);
}
我想找到一种方法来为此函数定义委托,最好是作为 LINQ 扩展,以避免重复代码。以下是这两种方法的当前用法示例:
public override void Average(IList<ThisType> samples)
{
TotalEntered = samples.Average(sample => sample.TotalEntered);
TotalExited = samples.Average(sample => sample.TotalExited);
MinimumContents = samples.Average(sample => sample.MinimumContents);
AverageContents = samples.Average(sample => sample.AverageContents);
MaximumContents = samples.Average(sample => sample.MaximumContents);
MinimumTime = samples.Average(sample => sample.MinimumTime);
AverageTime = samples.Average(sample => sample.AverageTime);
MaximumTime = samples.Average(sample => sample.MaximumTime);
StdDevTime = samples.Average(sample => sample.StdDevTime);
AverageNonZeroTime = samples.Average(sample => sample.AverageNonZeroTime);
PercentageWithinLimit = samples.Average(sample => sample.PercentageWithinLimit);
base.Average(samples);
}
public override void StandardDeviation(IList<ThisType> samples)
{
TotalEntered = samples.StandardDeviation(sample => sample.TotalEntered);
TotalExited = samples.StandardDeviation(sample => sample.TotalExited);
MinimumContents = samples.StandardDeviation(sample => sample.MinimumContents);
AverageContents = samples.StandardDeviation(sample => sample.AverageContents);
MaximumContents = samples.StandardDeviation(sample => sample.MaximumContents);
MinimumTime = samples.StandardDeviation(sample => sample.MinimumTime);
AverageTime = samples.StandardDeviation(sample => sample.AverageTime);
MaximumTime = samples.StandardDeviation(sample => sample.MaximumTime);
StdDevTime = samples.StandardDeviation(sample => sample.StdDevTime);
AverageNonZeroTime = samples.StandardDeviation(sample => sample.AverageNonZeroTime);
PercentageWithinLimit = queueSamples.StandardDeviation(sample => sample.PercentageWithinLimit);
base.StandardDeviation(samples);
}
我尝试为这些方法创建一个委托,如下:
public delegate double CollectiveOperation<T>(IEnumerable<T> source, Func<T, double> selector);
用于以下替换上述近乎重复的代码:
public void Operation(IList<ThisType> samples, LINQExtensions.CollectiveOperation<ThisType> Operation)
{
BufferMinimumTime = samples.Operation(sample => sample.BufferMinimumTime);
BufferAverageTime = samples.Operation(sample => sample.BufferAverageTime);
BufferMaximumTime = samples.Operation(sample => sample.BufferMaximumTime);
BufferStdDevTime = samples.Operation(sample => sample.BufferStdDevTime);
TotalMinimumTime = samples.Operation(sample => sample.TotalMinimumTime);
TotalAverageTime = samples.Operation(sample => sample.TotalAverageTime);
TotalMaximumTime = samples.Operation(sample => sample.TotalMaximumTime);
TotalStdDevTime = samples.Operation(sample => sample.TotalStdDevTime);
base.Operation(samples);
}
但是,我无法通过这些代表调用Average 或StandardDeviation,大概是因为this 关键字。从 StandardDeviation 实现中删除它并将调用替换为以下内容:
BufferMinimumTime = Operation(samples, sample => sample.BufferMinimumTime);
它仍然不适合委托,产生以下错误消息:
Expected a method with 'double StandardDeviation(IEnumerable<ThisType>, Func<ThisType, double>)' signature.
我有什么方法可以为上述通用静态 LINQ 扩展创建委托吗?这些方法将以独特的方式在各种类中使用,因此它们必须是通用的。
【问题讨论】:
-
我设法让它与您对
CollectiveOperation<T>和StandardDeviation<T>、库存Enumerable.Average<T>的定义以及T的小型测试类一起使用。您能否将您的问题浓缩为一个示例,其中包含重现问题所需的最少代码量? -
首先你的
StandardDeviation扩展应该使用yield return而不是完整的collection return,在网上查找。其次,您可以使用反射并获取样本中名称与本地成员匹配的成员列表,然后调用平均方法将结果分配给本地成员。 -
@Franck
StandardDeviation只需要返回单个值而不是序列时如何使用yield return? -
哦,我明白你的意思,但看到他需要连续调用该列表 12 次,这对我来说是一次迭代,很容易在方法中作为列表并返回相同的列表计算出来的。
标签: c# .net linq delegates anonymous-function