Pourquoi ai-je une exception de référence null dans cet arbre d'expression?

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

Question

J'ai une expression d'arbre qui ressemble à ceci:

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

Voici les types personnalisés utilisés dans l'arbre des expressions:

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

public class MyType2
{
}

Enfin, voici comment je construis, compile et appelle l'arborescence des expressions (cela ne fonctionnera pas exactement de la même manière car j'ai oublié du code pour simplifier les choses):

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

L'appel lève toutefois l'exception suivante:

La référence d'objet n'est pas définie à une instance d'un objet. à lambda_method (Closure, Object)

Je pense que cela se produit à cause de $result = (MyType2)((MyType1)$instance).Property1; affectation, mais je ne comprends pas pourquoi, car l'instance transmise à l'expression n'est pas null .

Réponse acceptée

Le fait que:

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

Est défini après tout le corps devrait être la clé; essentiellement, vous ne regardez même pas l'objet que vous passez; vous ne faites que regarder instanceParameter , qui est (dans votre code) simplement une variable non affectée.

En gros, supprimez la dernière déclaration de parameter et ne déclarez pas instanceParameter tant que variable:

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

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



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi