Following code to do a simple property assignment person.Name = "Joe Bloggs"
by dynamically creating a method using an Expression Tree fails with a NullReferenceException
- it's like the person
parameter I create isn't being passed in.
Any ideas?
class Person
{
public string Name { get; set; }
}
static void ExpressionTest()
{
var personParam = Expression.Parameter(typeof(Person), "person");
var block = Expression.Block(new[] { personParam },
Expression.Assign(
Expression.Property(personParam, "Name"), Expression.Constant("Joe Bloggs"))
);
/*
* block.DebugView in debugger shows:
*
* .Block(MyProject.MyNamepace.Person $person) {
* $person.Name = "Joe Bloggs"
* }
*
*/
var method = Expression.Lambda<Action<Person>>(block, personParam).Compile();
var person = new Person();
method(person); // **throws** System.NullReferenceException: ... at lambda_method(Closure , Person )
Debug.WriteLine(person.Name); // I expect this to print "Joe Bloggs"
}
Thanks for the great answers, I saw @decPL's first that led me to removing the new[] { personParam }
from the Expression.Block
call.
It all makes complete sense that a Block
scopes variables and you need to define them first (like some languages force you to) - my problem was that I didn't need any variables but was led astray by the magic DebugView
property that the debugger shows you into thinking that they were parameters, and the Block
was like a function definition:
.Block(MyProject.MyNamepace.Person $person) {
$person.Name = "Joe Bloggs"
}
... which of course it isn't. It's a block of code as the name suggests duh!
To clarify, BlockExpression represents a sequence of expressions that are executed sequentially, and returns the value of the last expression.
The version of Expression.Block
you are using "creates a BlockExpression that contains the given variables and expressions." (http://msdn.microsoft.com/en-us/library/dd324074(v=vs.110).aspx) hence it creates code:
{
Person person;
person.Name = "Joe Bloggs";
}
So it clearly throws NullReferenceException.
It works as expected if you remove the block:
var personParam = Expression.Parameter(typeof(Person), "person");
var method = Expression.Lambda<Action<Person>>(Expression.Assign(
Expression.Property(personParam, "Name"), Expression.Constant("Joe Bloggs")), personParam).Compile();
to fix your original code, you should remove the parameter expression passed to the block:
var block = Expression.Block(
Expression.Assign(
propertyExpr, Expression.Constant("Joe Bloggs"))
);
You're passing the parameter of your method to the Expression.Block method as a variable, which it is not. If you remove it, it will work correctly:
var block = Expression.Block(
Expression.Assign(
Expression.Property(personParam, "Name"),
Expression.Constant("Joe Bloggs")));
Of course, if that's the extent of your program, you may just as well drop the block expression.
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