5

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

aloisdg
  • 22,270
  • 6
  • 85
  • 105
Arian
  • 12,793
  • 66
  • 176
  • 300
  • You link to a (seemingly random) variety of how expressions can be used. But I'm sure there are more specific ones that exactly tackle your problem. – Gert Arnold Nov 12 '17 at 12:33
  • @GertArnold Yes you are right, but I don't want to repeat answers to these type of questions: "Why you want dynamic Expression?", "Why You want to create expression using `Expression Tree`, ... – Arian Nov 12 '17 at 12:35
  • I don't see how the links answer these questions should anyone feel inclined to ask them (which I'm not). I'm only trying to say that there are must be exact duplicates of your question. – Gert Arnold Nov 12 '17 at 12:40

1 Answers1

7

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);
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    God knows how many time I refresh this page to see an answer.Thank you Mr. Gravell. You are great. I will test it tomorrow and I will say the result. – Arian Nov 12 '17 at 19:24
  • But for my knowledge what reflector you used? You give it the assembly or class? How you get that result? – Arian Nov 12 '17 at 19:26
  • @Arian note I've updated the code; here's reflector doing the hard work - load the assembly, find the method (`Main` in this case) and select "decompile": https://i.stack.imgur.com/c3ZEX.png – Marc Gravell Nov 12 '17 at 19:32
  • Great Great Great – Arian Nov 13 '17 at 04:51
  • Thx to @MarcGravell. I didn't know about this decompile "Trick". Thats a really nice approach! Have to try this by myself. – VSDekar Dec 08 '17 at 06:42