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?
In 2010, the Dynamic Type was introduced and that gave us the ability to create dynamic lambda expressions.
Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y . You can compile and run code represented by expression trees.
That's the basics of building an expression tree in memory. More complex trees generally mean more node types, and more nodes in the tree. Let's run through one more example and show two more node types that you will typically build when you create expression trees: the argument nodes, and method call nodes.
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:
CallSiteBinder
that obtains the value of the dynamic property Name
of the dynamic object passed as argumentCallSiteBinder
that obtains the value of the dynamic property Surname
of the dynamic object passed as argumentstring.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 });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With