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

4

我有一些JSON需要在C#中进行排序。我正在尝试使用System.Linq.DynamicJObject列表进行排序,但是我无法让它与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 实例进行排序?

2个回答

2
您可以使用来自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

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

New answer

使用System.Linq.Dynamic无法实现这个。如果要访问JObject的属性,则需要调用Property方法。但是,System.Linq.Dynamic不支持此操作。根据文档的解释:表达式语言限制了对公共访问类型中声明的方法和构造函数的调用。
此外,表达式语言定义了一组基本类型和可访问类型。只有在这些类型中声明的方法才能在表达式中调用。

太完美了!让我免去了实现可怕的黑客行为的烦恼。 - tponthieux

1
您可以按照以下方式实现自己的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());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接