J'ai une expression d'arbre qui ressemble à ceci:Pourquoi est-ce que j'obtiens une exception de référence nulle dans cet arbre d'expression?
.Block(
System.Object $instance,
MyType2 $result) {
$result = (MyType2)((MyType1)$instance).Property1;
.Goto return { };
.Label
.LabelTarget useDefault:;
$result = .Default(MyType2);
.Label
.LabelTarget return:;
$result
}
Ce sont les types personnalisés qui sont utilisés dans l'arbre d'expression:
public class MyType1
{
public MyType2 Property1 { get; set; }
}
public class MyType2
{
}
Enfin, voici comment je construis, compiler et invoquer l'arbre d'expression (cela ne fonctionne pas exactement comme ça parce que j'ai laissé de 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);
Invoke lance l'ex suivant Ception cependant:
La référence d'objet n'est pas définie sur une instance d'un objet. à lambda_method (fermeture, objet)
Je pense que ce qui se passe en raison de l'affectation $result = (MyType2)((MyType1)$instance).Property1;
mais je ne comprends pas pourquoi, parce que l'instance qui est passé à l'expression n'est pas null
.
Merci Marc, qui a fait l'affaire. J'étais convaincu que le compilateur ne pouvait pas distinguer les arguments passés (si j'avais passé des arguments supplémentaires) alors j'ai ajouté le 'instanceParameter' au bloc. Mais maintenant je vois que c'est évident à partir des paramètres de type 'Func'. –
Merci encore de m'avoir aidé. La question était étroitement liée à un article de blog que j'écrivais à http://blog.subspace.nl/post/Getting-rid-of-null-checks-in-property-chains.aspx, qui pourrait vous intéresser. –