我有以下代码,并尝试避免代码重复 我想做的是有一个自定义扩展方法称为“SelectGrouped”
接受“Shift”对象,并返回匿名类型(不确定是否可能)
var groupedFillingsCurrentShift = currentShift.FilingMeasurements
.Where(f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == ShiftEnd)
.GroupBy(f => new { f.Medium, f.MeasurementTime })
.Select(t => new { t.Key.Medium, t.Key.MeasurementTime, VolumeInTanks = t.Sum(s => s.Filing) })
.ToList();
if (previousShift != null)
{
var groupedFillingsPreviousShift = previousShift.FilingMeasurements
.Where(f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == previousShift.ShiftEnd)
.GroupBy(f => new { f.Medium, f.MeasurementTime })
.Select(t => new { t.Key.Medium, t.Key.MeasurementTime, VolumeInTanks = t.Sum(s => s.Filing) })
.ToList();
我想要达到的目的是让它看起来像这样
var groupedResultCurrentShift =
currentShift.SelectGrouped(t=>t.Medium, t.MeasurementTime, t.VolumenInTanks);
var groupedResultPreviousShift =
previousShift.SelectGrouped(t=>t.Medium, t.MeasurementTime, t.VolumenInTanks);
答案 0 :(得分:2)
不幸的是,你想要的东西不能以现在的形式完成。
首先,变量t
仅在lambda中具有值。逗号分隔参数,因此t
会丢失其他参数的范围。
其次,更重要的是,匿名类型按定义在本地范围内,因为您必须使用“var”来暗示保存它们的变量的类型。您不能将它们作为参数传递,也不能将它们作为返回值返回(从技术上讲,您可以使用dynamic
,但是不要去那里,请)。
如果您要定义一个可用于保存投影数据的最终形式的命名类型,这将起作用:
internal class VolumeData
{
public string Medium;
public DateTime MeasurementTime;
public decimal VolumeInTanks;
}
public static List<VolumeData> GetVolumeData(this Shift shift)
{
return shift.FilingMeasurements
.Where(f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == ShiftEnd)
.GroupBy(f => new { f.Medium, f.MeasurementTime })
.Select(t => new VolumeData{
Medium = t.Key.Medium,
MeasurementTime = t.Key.MeasurementTime,
VolumeInTanks = t.Sum(s => s.Filing) })
.ToList();
}
...
var groupedFillingsCurrentShift = currentShift.GetVolumeData();
if (previousShift != null)
var groupedFillingsPreviousShift = previousShift.GetVolumeData();
答案 1 :(得分:0)
var groupedResultCurrentShift =
currentShift.SelectGrouped(t=>t.Medium, t.MeasurementTime, t.VolumenInTanks);
没有意义,因为第二个和第三个子句的t
未定义,VolumenInTanks
与尚未创建的属性相关。
我们也遇到了一个问题,因为查询中的Select
与之前在同一范围内定义的匿名对象有关。这阻止我们定义一个允许我们传入lambda的方法,该lambda定义了应该选择的内容。
然而:
currentShift.FilingMeasurements
.Where(f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == ShiftEnd)
.GroupBy(f => new { f.Medium, f.MeasurementTime })
.Select(t => new { t.Key.Medium, t.Key.MeasurementTime, VolumeInTanks = t.Sum(s => s.Filing) })
.ToList();
相当于;
currentShift.FilingMeasurements
.Where(f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == ShiftEnd)
.GroupBy(f => new { f.Medium, f.MeasurementTime }, s => s.Filing)
.Select(t => new { t.Key.Medium, t.Key.MeasurementTime, VolumeInTanks = t.Sum() })
.ToList();
现在,这仍然不存在,但让我们考虑从以下方面获得相同的信息:
currentShift.FilingMeasurements
.Where(f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == ShiftEnd)
.GroupBy(f => new { f.Medium, f.MeasurementTime }, s => s.Filing)
.Select(t => new { t.Key, VolumeInTanks = t.Sum() })
.ToList();
因此。如果您愿意item.Key.Medium
而不是item.Medium
,那么我们就会开展业务:
我们需要一个返回类型,因此我们将创建一个:
public class GroupedCount<T>
{
public<T> Key{get;set;}
public int Count{get;set;}//bit more of a general-purpose name than VolumeInTanks
}
现在,创建我们的方法:
public static List<GroupedCount<TKey>> ToGroupedCounts<TSource, TKey>(this IQueryable<TSource> source, Func<TSource, bool> pred, Func<TSource, TKey> keyGen, Func<TSource, int> tallyGen)
{
currentShift.FilingMeasurements
.Where(pred)
.GroupBy(keyGen, tallyGen)
.Select(t => new GroupedCount<TKey>{ Key = t.Key, Count = t.Sum() })
.ToList();
}
我们现在可以致电:
currentShift.ToGroupedCounts(
f => TimeSpan.Parse(f.MeasurementTime.MeasurementTime) == ShiftEnd,
f => new { f.Medium, f.MeasurementTime },
s => s.Filing
);
由于我们希望这是通用的,并且除非在特定情况下确实需要ToList()
,否则不应该调用public static IQueryable<GroupedCount<TKey>> ToGroupedCounts<TSource, TKey>(this IQueryable<TSource> source, Func<TSource, bool> pred, Func<TSource, TKey> keyGen, Func<TSource, int> tallyGen)
{
currentShift.FilingMeasurements
.Where(pred)
.GroupBy(keyGen, tallyGen)
.Select(t => new GroupedCount<TKey>{ Key = t.Key, Count = t.Sum() });
}
,返回IQueryable更有意义:
{{1}}