2010-05-01 84 views
1

我正在編寫一個表達式解析器,以使我的API更易於重構,並且不易出錯。 basicaly,我希望用戶寫這樣的代碼:的嘗試編譯Lambda表達式時出現InvalidOperationException(Lambda參數不在範圍內)

repository.Get(entity => entity.Id == 10); 

代替:

repository.Get<Entity>("Id", 10); 

從二進制表達的左側提取成員的名字是直線前進。 當我試圖從表達式的右側提取值時,問題就開始了。 上面的代碼片段演示了一個最簡單的情況,它涉及一個常量值 ,但涉及閉包的情況可能更復雜,而不是更復雜的情況。

在玩了一段時間後,我放棄了試圖覆蓋所有可能的情況,我自己 ,並決定使用該框架來編譯和執行表達式的右側來完成所有繁重的工作。 代碼的相關部分看起來像這樣:

public static KeyValuePair<string, object> Parse<T>(Expression<Func<T, bool>> expression) 
{ 
    var binaryExpression = (BinaryExpression)expression.Body; 

    string memberName = ParseMemberName(binaryExpression.Left); 
    object value = ParseValue(binaryExpression.Right); 

    return new KeyValuePair<string, object>(memberName, value); 
} 

private static object ParseValue(Expression expression) 
{ 
    Expression conversionExpression = Expression.Convert(expression, typeof(object)); 
    var lambdaExpression = Expression.Lambda<Func<object>>(conversionExpression); 
    Func<object> accessor = lambdaExpression.Compile(); 
    return accessor(); 
} 

現在,我得到的編譯行一個InvalidOperationException(範圍LAMBDA參數不是)。當我搜索解決方案時,我想出了類似的問題,涉及到手動構建表達式而不是提供所有片斷,或試圖依賴具有相同名稱和不同參考的參數。我不認爲這是這種情況,因爲我正在重複使用給定的表達式。

EDIT

這是的非工作情形之一:

ExpressionParser.Parse(實體=> entity.InternalClass.Id == entity.Id);

我很感激,如果有人會給我一些指示。 謝謝。

回答

1

帶常量的版本可以正常工作,並且發佈的代碼也可以正常工作。你能舉例說明一個不起作用的例子嗎?

當你看到這個,這意味着你的Right正在嘗試使用一個參數;在Expression<Func<T, bool>>(第一個,T類型)中只有一個參數。例如,我期望下面的內容被打破(而且它確實):

 // find people who are their own boss 
     var pair = Parse<Foo>(entity => entity.Id == entity.ManagerId); 

重新複雜性;有一個很多案件可以解析沒有編譯;我使用「嘗試並回退編譯」策略。參見EvaluateTryEvaluate方法,here

+0

嘿馬克,謝謝你的回答。這正是我遇到問題的那種表達方式。在給定的情況下,您的TryEvaluate也會失敗(請參閱編輯的問題)。當我回到Compile時,我遇到了上述異常。 – 2010-05-01 11:33:16

+0

@Moshe - 好的,它會的。除非你同時傳遞實例,否則你*不能*做你正在問的東西。而且你這樣做,只需將它編譯爲'Func '並調用在實例中傳遞的委託。你會期望它從哪裏獲得價值? – 2010-05-01 19:09:50