Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何让用户在运行时指定在Linq to Objects GroupBy查询表达式中使用哪些实体属性?_C#_Linq - Fatal编程技术网

C# 如何让用户在运行时指定在Linq to Objects GroupBy查询表达式中使用哪些实体属性?

C# 如何让用户在运行时指定在Linq to Objects GroupBy查询表达式中使用哪些实体属性?,c#,linq,C#,Linq,背景故事: 所以我有一个我正在开发的小演示应用程序,它正在浏览歌曲,并试图根据用户指定的标签找到重复的歌曲。最初,我只是使用下面的查询,我试图对其进行概括 var query = MusicFiles.GroupBy(x => new { x?.Tag.FirstArtist, x?.Tag.Title } ).Where(g => g.Count() > 1) .ToList(); 现在,虽然我想让用户指定这些属性,但我使用反射来获取Tag

背景故事:

所以我有一个我正在开发的小演示应用程序,它正在浏览歌曲,并试图根据用户指定的标签找到重复的歌曲。最初,我只是使用下面的查询,我试图对其进行概括

var query = MusicFiles.GroupBy(x => 
        new { x?.Tag.FirstArtist, x?.Tag.Title }
    ).Where(g => g.Count() > 1)
    .ToList();
现在,虽然我想让用户指定这些属性,但我使用反射来获取
TagLib.Tag
类的所有属性,现在允许用户指定他们感兴趣的标记

问题:

我如何使用这个新的字符串列表,通过表示类和组的属性所有这些属性,或者我如何概括上面的代码行


我最初的思路和我尝试的是尝试创建一个匿名对象,如上面所述,并使用反射来获取每个属性,但是,由于我迭代了一个字符串属性列表,因此每个属性都有一个匿名对象,而不是所有选定属性的匿名对象。我只是为透视表样式的报告构建了类似的内容,现在无法与您共享。我的建议是从包含所有可能分组字段的模板group by表达式开始。然后创建一个
ExpressionVisitor
以查找
MemberInitExpression
,并删除用户未选择的
MemberBinding
。这样,您仍然有一个强类型的groupby表达式,它可以使用efcore的任何特性,而无需重新实现它

表达式模板=x=>
新标记组{x?.Tag.FirstArtist,x?.Tag.Title,…};
公共筛选器:ExpressionVisitor{
公共筛选器(…选择){…}
受保护的重写表达式VisitMemberInit(MemberInitExpression节点){
返回node.Update(node.NewExpression,node.Bindings.Where(…);
}
}
var groupBy=新过滤器(选择)。访问(模板);

填空作为练习。

使用
动态Linq
库,该库提供接受字符串参数的Linq扩展方法来指定对象成员,而不是
Func
表达式
,然后遵循本QA中的建议:

它可以通过第三方“维护”版本的Microsoft原始官方
System.Linq.Dynamic.dll
程序集在NuGet上以
Install Package System.Linq.Dynamic.Core
Install Package System.Linq.Dynamic
的形式提供,并在GitHub上镜像:(此处提供较旧版本:)

在.NET标准的较新版本中,您需要的扩展方法是

那么您的查询将变成:

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();
使用System.Linq.Dynamic.Core;
[...]
IReadOnlyList userSelectedPropertyList=。。。
//例如,userSelectedPropertyList=new[]{“FirstArtist”,“Title”};
String dynamicLinqGroupByKeySelector=“新建(“+String.Join(“,”,userSelectedPropertyList)+”);
//因此GroupByKeySelector看起来像“新的(第一个艺术家,标题)”。
var query=MusicFiles
.GroupBy(dynamicLinqGroupByKeySelector)
.Where(g=>g.Count()>1)
.ToList();