9

I want to convert this:

Func<dynamic, object> myFunc = t => return t.Name + " " + t.Surname;

Into an Expression Tree.

What I have came up with, is this:

ParameterExpression target = ExpressionParameter(typeof(dynamic), "target");
ParameterExpression result = ExpressionParameter(typeof(object), "result");
BlockExpression block = Expression.Block(
     new [] { result },
     Expression.Assign(
           result,
           Expression.Add(
                 Expression.Add(
                      Expression.Property(target, "Name"),
                      Expression.Constant(" ", typeof(string))
                 ),
                 Expression.Property(target, "Surname")
           )
     )
);
Func<dynamic, object> myFunc = Expression.Lambda<dynamic, object>>(block, target).Compile();

However, the compiler doesn't like typeof(dynamic), and I kind of get it. dynamic isn't a type, it is an object in essence.

So I proceeded to change the ParameterExpression:

ParameterExpression target = ExpressionParameter(typeof(object), "target");

The code now compiles, but there is a problem at runtime.

I am trying to get the value of the property Name of target, which may have sense if the object was dynamic.

But since target is considered of type object, the Expression throws an error telling me Name doesn't exist as a property.

Is there an Expression for fetching a dynamic property?

Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • Have a look at this question : http://stackoverflow.com/questions/3562088/c-sharp-4-dynamic-in-expression-trees it deals with dynamic and expression tree – Cyril Durand Apr 29 '15 at 12:54

1 Answers1

6

For those who are or were interested in a solution:

ParameterExpression target = Expression.Parameter(typeof(object), "target");
ParameterExpression result = Expression.Parameter(typeof(object), "result");

CallSiteBinder getName = Binder.GetMember(
   CSharpBinderFlags.None, "Name", typeof(Program),
   new CSharpArgumentInfo[] {
       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
   }
);

CallSiteBinder getSurname= Binder.GetMember(
   CSharpBinderFlags.None, "Surname", typeof(Program),
   new CSharpArgumentInfo[] {
       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
   }
);

BlockExpression block = Expression.Block(
    new[] { result },
    Expression.Assign(
        result,
        Expression.Call(typeof(string).GetMethod("Concat", new Type[] { typeof(object[]) }),
                        Expression.NewArrayInit(typeof(object),
                             Expression.Dynamic(getName, typeof(object), target),
                             Expression.Constant(" ", typeof(object)),
                             Expression.Dynamic(getSurname, typeof(object), target)
                        )
       )
    )
);

Func<dynamic, object> myFunc = Expression.Lambda<Func<dynamic, object>>(block, target).Compile();

Here's exactly what I am doing:

  1. Created a CallSiteBinder that obtains the value of the dynamic property Name of the dynamic object passed as argument
  2. Created a CallSiteBinder that obtains the value of the dynamic property Surname of the dynamic object passed as argument
  3. Invoked the method string.Concat(params object[] args). For that, I need to send my arguments as an array of object. I'm creating the array with the values of getName, " ", and getSurname.

I used the following answer as a guide and reference:

C# 4 “dynamic” in expression trees

With the above approach, one could do something like this:

dynamic person = new ExpandoObject();
person.Name = "Matt";
person.Surname = "Smith";

object value = myFunc(person);
Console.WriteLine(value); //Will print out "Matt Smith"

//Internally it just calls:
//string.Concat(new object[] { person.Name, " ", person.Surname });
Community
  • 1
  • 1
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • Why the block expression? you could simply have a the body of the lambda be your call to concat, no? Why the expression tree, if you compile it at the end anyways??? – MBoros May 06 '15 at 06:20