Search code examples
c#linqlambdaexpression-treesc#-6.0

Create Lambda Expression Selector For New Class Using Expression Tree


Related To:

Create Expression Tree For Selector

Create a Lambda Expression With 3 conditions

Convert Contains To Expression Tree

Convert List.Contains to Expression Tree

I want to Create Selector expression using Expression Tree for new class. Please Consider this code:

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

I have big class (MyClass) that I want to select some of it's Properties. But I want to create it dynamically. How I can do this?

Thanks


Solution

  • The way to approach this is to write the equivalent code, then decompile it. For example:

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

    Now, if I compile this and decompile it with "reflector", I get:

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

    Note: memberof and methodof don't actually exist in C# - you can either manually get the method infos via reflection, or use Expression.PropertyOrField. We can thus rewrite it as:

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