开发者

Why do I get a null reference exception in this expression tree?

开发者 https://www.devze.com 2023-01-10 06:31 出处:网络
I have a tree expression that looks like this: .Block( System.Object $instance, MyType2 $result) { $result = (MyType2)((MyType1)$instance).Property1;

I have a tree expression that looks like this:

.Block(
    System.Object $instance,
    MyType2 $result) {
    $result = (MyType2)((MyType1)$instance).Property1;
    .Goto return { };
    .Label
    .LabelTarget useDefault:;
    $result = .Default(MyType2);
    .Label
    .LabelTarget return:;
    $result
}

These are the custom types that are used in the expression tree:

public class MyType1
{
    public MyType2 Property1 { get; set; }
}

public class MyType2
{
}

Finally, this is how I build, compile and invoke the expression tree (this won't run exactly like this because I've left out some code to simplify things):

object instance = new MyType1();

Expression expression = ... // n => n.Property1

ParameterExpression instanceParameter = Expression.Variable(
    typeof(object), "instance");
ParameterExpression resultVariable = Expression.Variable(
    typeof(MyType2), "result");

LabelTarget useDefaultLabel = Expression.Label("useDefault");
LabelTarget returnLabel = Expression.Label("return");

List<Expression> targetFragments = new List<Expression>();

MemberInfo memberInfo = (MemberInfo)expression.Body.Member;

MemberExpression member = ConstantExpression.MakeMemberAccess(
    Expression.Convert(instanceParameter, memberInfo.DeclaringType),
    memberInfo);

targetFragments.Add(
    Expression.Assign(
        resultVariable,
        Expression.Convert(member, typeof(MyType2))));

targetFragments.Add(Expression.Goto(returnLabel));
targetFragments.Add(Expression.Label(useDefaultLabel));
targetFragments.Add(Expression.Assign(resultVariable,
    Expression.Default(typeof(MyType2))));
targetFragments开发者_JAVA百科.Add(Expression.Label(returnLabel));

targetFragments.Add(resultVariable);

Expression finalExpression = Expression.Block(
    new[] { instanceParameter, resultVariable },
    targetFragments);

ParameterExpression parameter = Expression.Variable(typeof(object));

MyType2 result = Expression.Lambda<Func<T, MyType2>>(expression, parameter)
    .Compile()(instance);

The invoke throws the following exception however:

Object reference not set to an instance of an object. at lambda_method(Closure , Object )

I think this is happening because of the $result = (MyType2)((MyType1)$instance).Property1; assignment but I don't understand why because the instance that is passed to the expression isn't null.


The fact that:

ParameterExpression parameter = Expression.Variable(typeof(object));

Is defined after all the body should be the clue; essentially, you simply aren't even looking at the object you pass in; you are only looking at instanceParameter, which is (in your code) simply an unassigned variable.

Basically, drop the final parameter declaration, and don't declare instanceParameter as a variable:

Expression finalExpression = Expression.Block(
    new[] { resultVariable },
    targetFragments);

MyType2 result = Expression.Lambda<Func<object, MyType2>>(
      finalExpression, instanceParameter).Compile()(instance);
0

精彩评论

暂无评论...
验证码 换一张
取 消