我有一个班级Product
:
class Product
{
int Id { get; set; }
string Name { get; set; }
int CategoryId { get; set; }
int PlantId { get; set; }
DateTime ProductionDate { get; set; }
}
我想在多个属性上使用LINQ GroupBy
但我事先并不知道有多少属性和属性。例如,我可能只想CategoryId
,PlantId
或两者都进行分组。我在网上发现了一篇描述如何use LINQ GrouBy dinamically的文章。
这可能确实很好但是如果我想在ProductionDate.Year
和ProductionDate.Month
上执行分组依据而不事先知道粒度?作为粒度,我的意思是我是否要对特定年份中生成的所有Products
进行分组,或者将该组缩小到该月。
我找到的唯一合理解决方案是:
public ProductInfo GetGroupedProducts(int? year, int? month, int? selectedCategoryId, int? selectedPlantId)
{
List<Product> products = GetProducts();
var groupedProducts = products.GroupBy(p => new { (year == null ? p.ProductionDate.Year : string.Empty),
(month == null ? p.ProductionDate.Month : string.Empty),
(selectedCategoryId == null ? p.CategoryId : string.Empty),
(selectedPlantId == null ? p.PlantId : string.Empty)
});
//perform some additional filtering and assignments
}
但我想可能会有一个更清洁,更合适的解决方案。使用旧式的构建查询的方式,基于字符串,这个任务更容易完成。如果没有别的办法,我真的认为这是LINQ
的一部分需要改进。
答案 0 :(得分:0)
更干净的解决方案是使用此扩展方法:
public static TResult With<TInput, TResult>(this TInput? o, Func<TInput, TResult>
selector, TResult defaultResult = default(TResult)) where TInput : struct
{
return o.HasValue ? selector(o.Value) : defaultResult;
}
像这样:
string result = year.With(T => p.ProductionDate.Year, string.Empty);
,如果空值可以:
string result = year.With(T => p.ProductionDate.Year);
如果T
有值,则或int
为int?
的内容。
但是,您知道,更好的解决方案是out there,因此请随意扩展您的代码,以便对其进行分析。
答案 1 :(得分:0)
如果我理解你的要求,我也有类似的问题Reversing typeof to use Linq Field<T>
我会做像
这样的事情public static IEnumerable<IGrouping<string, TElement>> GroupMany<TElement>(
this IEnumerable<TElement> elements,
params Func<TElement, object>[] groupSelectors)
{
return elements.GroupBy(e => string.Join(":", groupSelectors.Select(s => s(e))));
}
然后你可以调用你的函数
var groupedProducts = products.GroupMany(p => p.CategoryId , p => p.ProductionDate.Month);
函数组通过一系列属性除以冒号。之所以这样做是因为字符串的哈希码保证与类相反。