使用表达式树为新类创建Lambda表达式选择器

5

你链接到了各种看似随机的正则表达式用法,但我相信一定有更具体的方法来解决你的问题。 - Gert Arnold
@GertArnold 是的,你说得对,但我不想重复回答这类问题:“为什么你想要动态表达式?”,“为什么你想要使用Expression Tree创建表达式...” - Arian
我不认为这些链接回答了这些问题,如果有人想问的话(我并不想问)。我只是想说,你的问题一定有确切的重复。 - Gert Arnold
1个回答

7

处理这个问题的方法是编写相应的代码,然后进行反编译。例如:

using System;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        ShowMeTheLambda<Foo, Allocation>(s => new Allocation
        {
            Id = s.Id,
            UnitName = s.UnitName,
            Address = s.NewAddress,
            Tel = s.NewTel
        });
    }
    static void ShowMeTheLambda<TFrom, TTo>(Expression<Func<TFrom, TTo>> lambda)
    { }
}
class Foo
{
    public int Id { get; set; }
    public string UnitName { get; set; }
    public string NewTel { get; set; }
    public string NewAddress { get; set; }
}
class Allocation
{
    public int Id { get; set; }
    public string UnitName { get; set; }
    public string Tel { get; set; }
    public string Address { get; set; }
}

现在,如果我使用“反编译器”编译并反编译它,我会得到:

private static void Main()
{
    ParameterExpression expression;
    MemberBinding[] bindings = new MemberBinding[] { Expression.Bind((MethodInfo) methodof(Allocation.set_Id), Expression.Property(expression = Expression.Parameter(typeof(Foo), "s"), (MethodInfo) methodof(Foo.get_Id))), Expression.Bind((MethodInfo) methodof(Allocation.set_UnitName), Expression.Property(expression, (MethodInfo) methodof(Foo.get_UnitName))), Expression.Bind((MethodInfo) methodof(Allocation.set_Address), Expression.Property(expression, (MethodInfo) methodof(Foo.get_NewAddress))), Expression.Bind((MethodInfo) methodof(Allocation.set_Tel), Expression.Property(expression, (MethodInfo) methodof(Foo.get_NewTel))) };
    ParameterExpression[] parameters = new ParameterExpression[] { expression };
    ShowMeTheLambda<Foo, Allocation>(Expression.Lambda<Func<Foo, Allocation>>(Expression.MemberInit(Expression.New(typeof(Allocation)), bindings), parameters));

}

注意:memberofmethodof在C#中实际上不存在 - 您可以通过反射手动获取方法信息,或使用Expression.PropertyOrField。因此,我们可以将其重写为:
ParameterExpression expression = Expression.Parameter(typeof(Foo), "s");
MemberBinding[] bindings = new MemberBinding[]
{
    Expression.Bind(typeof(Allocation).GetProperty(nameof(Allocation.Id)), Expression.PropertyOrField(expression, nameof(Foo.Id))),
    Expression.Bind(typeof(Allocation).GetProperty(nameof(Allocation.UnitName)), Expression.PropertyOrField(expression, nameof(Foo.UnitName))),
    Expression.Bind(typeof(Allocation).GetProperty(nameof(Allocation.Address)), Expression.PropertyOrField(expression, nameof(Foo.NewAddress))),
    Expression.Bind(typeof(Allocation).GetProperty(nameof(Allocation.Tel)), Expression.PropertyOrField(expression, nameof(Foo.NewTel))),
};
ParameterExpression[] parameters = new ParameterExpression[] { expression };
var lambda = Expression.Lambda<Func<Foo, Allocation>>(Expression.MemberInit(Expression.New(typeof(Allocation)), bindings), parameters);

1
上帝知道我刷新了多少次这个页面才看到答案。谢谢Gravell先生,您真是太棒了。我明天会测试一下并公布结果。 - Arian
但是就我的了解,您使用了哪个反射器?您将其提供给程序集还是类?您是如何得到这个结果的? - Arian
@Arian 注意,我已经更新了代码;这里是反编译器在做重活 - 加载程序集,找到方法(在这种情况下是“Main”)并选择“反编译”:https://i.stack.imgur.com/c3ZEX.png - Marc Gravell
太棒了! - Arian
感谢@MarcGravell。我之前不知道这个反编译“技巧”。这是一个非常不错的方法!我必须自己试一试。 - VSDekar

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