通过使用表达式树动态创建方法来执行简单的属性赋值person.Name = "Joe Bloggs"
以及NullReferenceException
失败 - 就像我创建的person
参数没有被传递一样英寸
有什么想法吗?
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"
}
感谢您提供了很好的答案,我首先看到@ decPL导致我从new[] { personParam }
电话中删除了Expression.Block
。
这一切都是完全合理的,Block
范围变量,你需要先定义它们(就像某些语言强迫你) - 我的问题是我不需要任何变量但被误入歧途调试器向您显示的魔术DebugView
属性,认为它们是参数,而Block
就像函数定义:
.Block(MyProject.MyNamepace.Person $person) {
$person.Name = "Joe Bloggs"
}
......当然不是。这是代码的块,顾名思义就是duh!
答案 0 :(得分:8)
为了阐明,BlockExpression表示按顺序执行的一系列表达式,并返回最后一个表达式的值。
您正在使用的Expression.Block
版本“创建一个包含给定变量和表达式的BlockExpression。” (http://msdn.microsoft.com/en-us/library/dd324074(v=vs.110).aspx)因此它创建了代码:
{
Person person;
person.Name = "Joe Bloggs";
}
所以它显然会抛出NullReferenceException。
答案 1 :(得分:4)
如果删除块,它会按预期工作:
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();
要修复原始代码,您应该删除传递给块的参数表达式:
var block = Expression.Block(
Expression.Assign(
propertyExpr, Expression.Constant("Joe Bloggs"))
);
答案 2 :(得分:1)
您将方法的参数作为变量传递给Expression.Block方法,而不是。如果删除它,它将正常工作:
var block = Expression.Block(
Expression.Assign(
Expression.Property(personParam, "Name"),
Expression.Constant("Joe Bloggs")));
当然,如果这是你的程序的范围,你也可以删除块表达式。