2010-08-01 23 views
1

我有一棵樹的表達,看起來像這樣:爲什麼我會在這個表達式樹中得到一個空引用異常?

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

的invoke拋出以下前但是:不知道:

未將對象引用設置爲對象的實例。在lambda_method(閉合,對象)

我想這是因爲$result = (MyType2)((MyType1)$instance).Property1;分配的發生,但我不明白爲什麼,因爲被傳遞到表達式的實例不是null

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

是所有身體之後定義應該是線索;:

回答

3

的事實基本上,你根本就不會看你傳入的對象;你只能看到instanceParameter,這是(在你的代碼中)只是一個未分配的變量。

基本上,降最後parameter申報,不申報instanceParameter作爲變量:

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

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

感謝馬克,該訣竅。我確信編譯器不能區分傳遞的參數(如果我傳遞了額外的參數),所以我在塊中添加了'instanceParameter'。但是現在我明白它可以來自'Func'類型參數。 – 2010-08-02 07:37:37

+0

再次感謝您的幫助。這個問題與我寫在http://blog.subspace.nl/post/Getting-rid-of-null-checks-in-property-chains.aspx上的一篇博文有很大的關係,這可能會讓你感興趣。 – 2010-08-05 21:19:12

相關問題