使用Dynamic Linq库运行求和
本文关键字:运行 求和 Linq Dynamic 使用 | 更新日期: 2023-09-27 18:20:51
给定以下列表:
var items = new List<int> { 1, 2, 3, 5 };
我正在尝试使用DynamicLinq库为任何给定的记录计算以前的记录总数。在标准LINQ(LINQ到对象)中,我可以这样做:
var runningTotal = 0;
var qry1 = items.Select(x => {
var ret = new { x, runningTotal };
runningTotal += x;
return ret;
});
或者这个(效率较低,因为它每次都在迭代列表中以前的所有项目。对于这样一个小列表来说,这显然不是问题,但对于较大的列表来说,它将是问题):
var qry1 = items.Select((x, idx) => new {
x,
runningTotal = items.Take(idx).Sum()
});
该库没有在字符串表达式中实现Take
,也没有实现采用元素索引的Select
重载。然而,以下内容几乎达到了目的:
var qry2 = items.AsQueryable().Select(
"new(it as x, @0.Where(it < parent).Sum(it) as runningTotal)",
items
);
然而,这有几个缺点:
- 列表必须有一定的顺序,否则内部
Where
将返回任意记录 - 出于同样的原因,每个项目都必须是唯一的
- 这与第二个C#示例的低效率相同
有没有任何方法可以使用DynamicLinq来做到这一点,它没有这些问题,如果有,那么如何?
更新
我试着写以下课程:
[DynamicLinqType]
public class Aggregator<T> {
private T state;
private Func<T, T, T> fn;
public Aggregator(Func<T, T, T> fn) {
this.fn = fn;
}
public T GetState(T value) {
state = fn(state, value);
return state;
}
}
然后像这样查询:
var aggregator = new Aggregator<int>((runningTotal1, x) => runningTotal1 + x);
var qry4 = items.AsQueryable().Select(
"new(it as x, @0.GetState(it) - it as runningTotal)",
aggregator
);
但是即使CCD_ 5方法是公共的,我也得到了CCD_。这是因为库限制自己只能使用某些预定义类型的成员,以及用DynamicLinqTypeAttribute
标记的类型(默认情况下)。但标记的类型Aggregator<T>
与构造的类型(Aggregator<int>
)不同。
更新2
我已经提交了一个关于运行计算的问题和另一个关于已识别类型的通用组合的问题。
我做了一点研究,发现哪里有错误:
DynamicLinqType
寄存器类型-在您的情况下为Aggregator<T>
因此,当您将T
指定为int时,这已经是另一种类型Aggregator<int>
,并且DynamicLinq
认为它没有预定义类型。
因此,作为一种解决方案,您可以删除通用部件:
[DynamicLinqType]
public class Aggregator
{
private int state;
private Func<int, int, int> fn;
public Aggregator(Func<int, int, int> fn)
{
this.fn = fn;
}
public int GetState(int value)
{
state = fn(state, value);
return state;
}
}
更新:
还有另一种方法-在源代码中修复此问题:
static bool IsPredefinedType(Type type)
{
if (_predefinedTypes.Contains(type)) return true;
if (GlobalConfig.CustomTypeProvider.GetCustomTypes().Contains(type)) return true;
// for generic type check GenericTypeDefinition
if (type.IsGenericType && GlobalConfig.CustomTypeProvider.GetCustomTypes().Contains(type.GetGenericTypeDefinition())) return true;
return false;
}