C# 按语句构建通用顺序

C# 按语句构建通用顺序,c#,generics,reflection,lambda,expression-trees,C#,Generics,Reflection,Lambda,Expression Trees,我有一个具有一系列属性的类: class Foo { public string Name {get; set; } public int Age {get; set; } using System; using System.Linq; using System.Linq.Expressions; class Foo { public string Name { get; } public int Age { get; } public Foo

我有一个具有一系列属性的类:

class Foo {
    public string Name {get; set; }
    public int Age {get; set; 
}
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();
    }
}
以及
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)
执行此代码将抛出

ArgumentException:为lambda提供的参数数量不正确 声明


问题是您试图构建一个
Func
,但对
表达式的调用。Lambda
没有指定参数表达式,这意味着您不能期望它创建一个具有任何参数的委托。只需指定
type
作为
Expression.Lambda的第二个参数即可。下面是一个基于您的问题的完整示例-请注意,我更改了年龄以证明它实际上是有序的,并且我已将您的字段更新为只读属性:

class Foo {
    public string Name {get; set; }
    public int Age {get; set; 
}
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();
    }
}

您不执行比较-
OrderBy
执行比较。如果愿意,可以传入自定义比较器,但通常不需要。到目前为止,您显示的代码会发生什么情况?调用
Compile()
时,它返回一个
ArgumentException:为lambda声明提供的参数数量不正确。那么这应该是一个问题:)如果您能解决这个问题,我怀疑它会正常工作。我强烈建议你把这个问题改写成一个问题,包括例外情况。我怀疑修复方法只是调用
Expression.Lambda(property,type)
,但如果我们有一个完整的示例,就很容易测试它。这仍然不是一个简短但完整的示例。我们应该有一个单一的文本块,我们可以复制,粘贴到一个新的文件,编译和运行。目前,我们必须从一个代码片段中复制Foo,然后使用
指令添加一组
,并使用另一个类(例如
Test
Program
)来包含其他方法。另外,您给出的例外只是消息,而不是堆栈跟踪。哦,顺便说一句,我强烈建议使用属性而不是公共字段。。。
Georg: 10
Hans: 12
Birgit: 40