Warum bekomme ich in diesem Ausdrucksbaum eine Null-Referenz-Ausnahme?

.net c# c#-4.0 expression-trees lambda

Frage

Ich habe einen Baumausdruck, der so aussieht:

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

Dies sind die benutzerdefinierten Typen, die in der Ausdrucksbaumstruktur verwendet werden:

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

public class MyType2
{
}

Schließlich erstelle, kompiliere und rufe ich den Ausdrucksbaum auf (das wird nicht genau so laufen, weil ich etwas Code weggelassen habe, um Dinge zu vereinfachen):

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

Der Aufruf löst jedoch die folgende Ausnahme aus:

Der Objektverweis wurde nicht auf eine Instanz eines Objekts festgelegt. bei lambda_method (Schließung, Objekt)

Ich denke, das passiert wegen der $result = (MyType2)((MyType1)$instance).Property1; Zuweisung, aber ich verstehe nicht warum, weil die Instanz, die an den Ausdruck übergeben wird, nicht null .

Akzeptierte Antwort

Die Tatsache, dass:

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

Ist definiert, nachdem der ganze Körper der Schlüssel sein sollte; im Wesentlichen, du schaust einfach nicht einmal auf das Objekt, das du passierst; Sie betrachten nur instanceParameter , was (in Ihrem Code) einfach eine nicht zugewiesene Variable ist.

Verwerfen Sie im Grunde die letzte parameter und deklarieren Sie instanceParameter als Variable:

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

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


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow