构建通用的 order-by-statement
Building generic order-by-statement
我有一个 class 有一堆属性:
class Foo {
public string Name {get; set; }
public int Age {get; set;
}
和 Foo
实例的集合。
现在我想按用户给定的 属性 对这些元素进行排序。所以用户从类型Foo
中选择了一个属性。现在我想根据这个 属性.
按元素排序
一种方法是基于反射的方法,与此类似:
var p = typeof(Foo).GetProperty("Age");
var ordered = fooList.OrderBy(x => (int) p.GetValue(x, null));
到目前为止这有效。但是我也尝试了第二个,但我被卡住了。它通过执行表达式树来处理,如下所示:
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f)
与
Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property).Compile();
}
我的问题是:我应该 return Func<T, int>
从哪里获得 int
部分,或者换句话说,从哪里以及如何执行实际比较?我想我必须从 CallExpression
到 IComparable.CompareTo
,但我不确定该怎么做。我想我需要访问这两个实例以进行比较。
编辑:完整代码示例
static void Main()
{
var fooList = new[] { new Foo("Hans", 10), new Foo("Georg", 12), new Foo("Birgit", 40) };
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f);
}
private static Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property).Compile();
}
执行这段代码会抛出一个
ArgumentException: Incorrect number of parameters supplied for lambda
declaration
问题是您正在尝试构建一个 Func<T, int>
但您对 Expression.Lambda
的调用没有指定参数表达式,这意味着您不能指望它创建一个委托有 任何参数。只需将 type
指定为 Expression.Lambda
的第二个参数即可。这是一个基于您的问题的完整示例 - 请注意,我已经更改了年龄以证明它确实在订购,并且我已将您的字段更新为只读属性:
using System;
using System.Linq;
using System.Linq.Expressions;
class Foo
{
public string Name { get; }
public int Age { get; }
public Foo(string name, int age)
{
this.Name = name;
this.Age = age;
}
}
class Test
{
static void Main()
{
var fooList = new[]
{
new Foo("Hans", 12),
new Foo("Georg", 10),
new Foo("Birgit", 40)
};
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f);
foreach (var item in ordered)
{
Console.WriteLine($"{item.Name}: {item.Age}");
}
}
private static Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property, type).Compile();
}
}
输出:
Georg: 10
Hans: 12
Birgit: 40
我有一个 class 有一堆属性:
class Foo {
public string Name {get; set; }
public int Age {get; set;
}
和 Foo
实例的集合。
现在我想按用户给定的 属性 对这些元素进行排序。所以用户从类型Foo
中选择了一个属性。现在我想根据这个 属性.
一种方法是基于反射的方法,与此类似:
var p = typeof(Foo).GetProperty("Age");
var ordered = fooList.OrderBy(x => (int) p.GetValue(x, null));
到目前为止这有效。但是我也尝试了第二个,但我被卡住了。它通过执行表达式树来处理,如下所示:
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f)
与
Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property).Compile();
}
我的问题是:我应该 return Func<T, int>
从哪里获得 int
部分,或者换句话说,从哪里以及如何执行实际比较?我想我必须从 CallExpression
到 IComparable.CompareTo
,但我不确定该怎么做。我想我需要访问这两个实例以进行比较。
编辑:完整代码示例
static void Main()
{
var fooList = new[] { new Foo("Hans", 10), new Foo("Georg", 12), new Foo("Birgit", 40) };
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f);
}
private static Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property).Compile();
}
执行这段代码会抛出一个
ArgumentException: Incorrect number of parameters supplied for lambda declaration
问题是您正在尝试构建一个 Func<T, int>
但您对 Expression.Lambda
的调用没有指定参数表达式,这意味着您不能指望它创建一个委托有 任何参数。只需将 type
指定为 Expression.Lambda
的第二个参数即可。这是一个基于您的问题的完整示例 - 请注意,我已经更改了年龄以证明它确实在订购,并且我已将您的字段更新为只读属性:
using System;
using System.Linq;
using System.Linq.Expressions;
class Foo
{
public string Name { get; }
public int Age { get; }
public Foo(string name, int age)
{
this.Name = name;
this.Age = age;
}
}
class Test
{
static void Main()
{
var fooList = new[]
{
new Foo("Hans", 12),
new Foo("Georg", 10),
new Foo("Birgit", 40)
};
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f);
foreach (var item in ordered)
{
Console.WriteLine($"{item.Name}: {item.Age}");
}
}
private static Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property, type).Compile();
}
}
输出:
Georg: 10
Hans: 12
Birgit: 40