使用动态 LINQ 按一个或多个属性对 JSON 进行排序

Posted

技术标签:

【中文标题】使用动态 LINQ 按一个或多个属性对 JSON 进行排序【英文标题】:Sort JSON by one or more properties using Dynamic LINQ 【发布时间】:2014-11-28 01:23:49 【问题描述】:

我有一些 JSON 需要在 C# 中进行排序。我正在尝试使用System.Linq.DynamicJObjects 列表进行排序,但我无法让它与Newtonsoft.Json.Linq.JObject 的实例一起使用。

这行得通:

public class Row

    public String Column1  get; set; 
    public Int32 Column2  get; set; 


var rows = new List<Row>();

rows.Add(new Row  Column1 = "B", Column2 = 2 );
rows.Add(new Row  Column1 = "B", Column2 = 1 );
rows.Add(new Row  Column1 = "A", Column2 = 2 );
rows.Add(new Row  Column1 = "A", Column2 = 1 );

var sortedRows = rows.AsQueryable().OrderBy("Column1, Column2");

这不是:

var rows = new List<JObject>();

var row1 = new JObject();
row1["Column1"] = "B";
row1["Column2"] = 2;
rows.Add(row1);

var row2 = new JObject();
row2["Column1"] = "B";
row2["Column2"] = 1;
rows.Add(row2);

var row3 = new JObject();
row3["Column1"] = "A";
row3["Column2"] = 2;
rows.Add(row3);

var row4 = new JObject();
row4["Column1"] = "A";
row4["Column2"] = 1;
rows.Add(row4);

var sortedRows = rows.AsQueryable().OrderBy("Column1, Column2");
//System.Linq.Dynamic.ParseException : No property or field 'Column1' exists in type 'JObject'

如何根据动态数量的属性对 JObject 实例进行排序?

【问题讨论】:

【参考方案1】:

您可以使用来自System.Dynamic.Linq 的索引器语法:

var sortedRows = rows.AsQueryable().OrderBy(@"it[""Column1""], it[""Column2""]");

旧答案

您无法使用System.Linq.Dynamic 执行此操作。要访问JObject 的属性,您需要调用Property 方法。但是,System.Linq.Dynamic 不允许这样做。来自文档:

表达式语言将方法和构造函数的调用限制为在可访问类型中声明为公共的那些。


表达式语言定义了以下原始类型

Object Boolean Char String SByte Byte Int16 UInt16 Int32 UInt32 Int64 UInt64 Decimal Single Double DateTime TimeSpan Guid

原始类型对应于 .NET Framework 基类库的 System 命名空间中类似命名的类型。表达式语言还定义了一组可访问类型,由原始类型和 System 命名空间中的以下类型组成:

Math Convert

可访问类型是唯一可以在表达式中显式引用的类型,表达式语言中的方法调用仅限于在可访问类型中声明的方法。

【讨论】:

这太完美了!使我免于实施可怕的黑客攻击。【参考方案2】:

您可以像这样实现自己的IComparer

public class MyJObjectComparer : IComparer<JObject>

    public int Compare(JObject a, JObject b)
    
        if ((a["Column1"] == b["Column1"]) && a["Column2"] == b["Column2"]))
            return 0;

        if ((a["Column1"] < b["Columnq"]) || ((a["Column1"] == b["Column1"]) && (a["Column2"] < b["Column2"])))
            return -1;

        return 1;
    

并像这样使用它:

var sortedRows = rows.AsQueryable().OrderBy(r => r, new MyJObjectComparer());

【讨论】:

以上是关于使用动态 LINQ 按一个或多个属性对 JSON 进行排序的主要内容,如果未能解决你的问题,请参考以下文章

C# LINQ - 按属性分组列表,然后按不同组选择

具有嵌套属性的动态 linq 表达式树

使用linq对多个进行分组[重复]

如何按整数属性对类列表进行排序? [复制]

C# LINQ 组按属性集合,然后按列表定义的显式顺序对每个组进行排序[重复]

使用LINQ按字母顺序比较字符串