为什么在此表达式树中出现空引用异常?

发布于 2024-09-12 13:14:23 字数 2168 浏览 2 评论 0原文

我有一个如下所示的树表达式:

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

这些是表达式树中使用的自定义类型:

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

public class MyType2
{
}

最后,这就是我构建、编译和调用表达式树的方式(这不会完全像这样运行,因为我已经省略了一些代码以简化操作):

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.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);

但是调用会抛出以下异常:

未将对象引用设置为对象的实例。在 lambda_method( 闭包 , 对象 )

我认为发生这种情况是因为 $result = (MyType2)((MyType1)$instance).Property1; 赋值,但我不明白为什么,因为该实例传递给表达式的值不为 null

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.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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

余生再见 2024-09-19 13:14:23

事实是:

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

毕竟定义的主体应该是线索;本质上,你根本就没有看你传入的对象;您只查看instanceParameter,它(在您的代码中)只是一个未分配的变量。

基本上,删除最后的 parameter 声明,并且不要将 instanceParameter 声明为变量:

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

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

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文