背景故事:
所以我有一个正在使用的演示应用程序,它正在浏览歌曲,并尝试根据用户指定的标签查找重复项。最初,我只是使用下面的查询来试图概括一下。
var query = MusicFiles.GroupBy(x =>
new { x?.Tag.FirstArtist, x?.Tag.Title }
).Where(g => g.Count() > 1)
.ToList();
现在,尽管我想让用户指定这些属性,所以我使用反射来获取TagLib.Tag
类的所有属性,现在允许用户指定他们感兴趣的标签。
问题:
如何使用新的字符串列表表示类的属性,并按所有这些属性分组,或者如何概括以上代码行。
我最初的思路和尝试过的工作是尝试创建一个像上面一样的匿名对象,并使用反射来获取每个属性,但是由于我要遍历字符串属性列表,所以我最终得到了一个匿名对象每个属性的对象,而不是所有选定属性的匿名对象
使用Dynamic-Linq
库提供Linq扩展方法,该方法接受字符串参数来指定对象成员,而不是Func<...>
和Expression<Func<...>>
,然后按照此QA中的建议进行操作:How to use GroupBy using Dynamic LINQ
[它可以通过Microsoft原始官方System.Linq.Dynamic.dll
程序集的第三方“维护”版本以Install-Package System.Linq.Dynamic.Core
或Install-Package System.Linq.Dynamic
的形式在NuGet上获得,并在GitHub上镜像到此处:https://github.com/StefH/System.Linq.Dynamic.Core/wiki/Dynamic-Expressions(旧版本可在此处获得:[C0 ])
在.NET Standard的最新版本中,所需的扩展方法是https://github.com/kahanu/System.Linq.Dynamic。
然后您的查询将成为:
GroupBy( this IQueryable source, String keySelector, params Object\[\] args )
我刚刚为数据透视表样式报表构建了类似的内容,目前无法与您分享。我的建议是从包含所有可能分组字段的表达式的模板开始。然后创建一个GroupBy( this IQueryable source, String keySelector, params Object\[\] args )
查找using System.Linq.Dynamic.Core;
[...]
IReadOnlyList<String> userSelectedPropertyList = ...
// e.g. userSelectedPropertyList = new[] { "FirstArtist", "Title" };
String dynamicLinqGroupByKeySelector = "new (" + String.Join( ", ", userSelectedPropertyList ) + ")";
// so the GroupBy keySelector looks like "new (FirstArtist, Title)".
var query = MusicFiles
.GroupBy( dynamicLinqGroupByKeySelector )
.Where( g => g.Count() > 1 )
.ToList();
,并删除用户没有选择的所有ExpressionVisitor
。这样,您仍然拥有一个强类型的按表达式分组,可以使用EF Core的任何功能而无需重新实现它。
MemberInitExpression
作为练习填补空白。