【问题标题】:Create Lambda Expression Selector For New Class Using Expression Tree使用表达式树为新类创建 Lambda 表达式选择器
【发布时间】:2018-04-25 05:08:51
【问题描述】:

相关:

Create Expression Tree For Selector

Create a Lambda Expression With 3 conditions

Convert Contains To Expression Tree

Convert List.Contains to Expression Tree

我想使用Expression Tree 为新类创建Selector 表达式。请考虑以下代码:

s => new Allocation
     {
         Id = s.Id,
         UnitName = s.UnitName,
         Address = s.NewAddress,
         Tel = s.NewTel
      }

我有一个大类 (MyClass),我想选择其中的一些属性。但我想动态创建它。我该怎么做?

谢谢

【问题讨论】:

  • 您链接到(看似随机的)各种表达方式的使用方式。但我敢肯定,还有更具体的方法可以完全解决您的问题。
  • @GertArnold 是的,你是对的,但我不想重复回答这些类型的问题:“为什么要使用动态表达式?”、“为什么要使用 Expression Tree 创建表达式, ...
  • 如果有人想问这些问题(我不是),我看不出这些链接如何回答这些问题。我只是想说您的问题必须完全相同。

标签: c# linq lambda expression-trees c#-6.0


【解决方案1】:

解决这个问题的方法是编写等效代码,然后对其进行反编译。例如:

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);

【讨论】:

  • 天知道我刷新这个页面多少次才能看到答案。谢谢 Gravell 先生。你很棒。我明天测试一下,我会说结果。
  • 但据我所知,您使用的反射器是什么?你给它组装还是上课?你是怎么得到这个结果的?
  • @Arian note 我已经更新了代码;这是反射器做艰苦的工作 - 加载程序集,找到方法(在这种情况下为Main)并选择“反编译”:i.stack.imgur.com/c3ZEX.png
  • 伟大伟大伟大
  • 感谢@MarcGravell。我不知道这个反编译“技巧”。这是一个非常好的方法!必须自己尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
相关资源
最近更新 更多