(對底部的回答)
我正在嘗試構建一個結合的系統
Func<T, bool>
委託給ExpressionTree,它允許我傳入一個值(在這種情況下為badValue)並在謂詞全部返回true並考慮二進制操作時獲取bool。這是我第一次使用Expression / ExpressionTrees,所以請保持溫和。
我收到這個錯誤:
ArgumentException:無法調用“System.Boolean”類型的表達式
在這條線上:
collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(...
我已經設置了那條線,因為我需要在所有表達式中共享對value
的引用(對嗎?)。
我理想的情況是只有一堆
Expression<Func<blah, blah, bool>>
我可以將它們與邏輯運算符(和/或/不)一起傳遞到系統中,並在最後得到一個bool。希望能夠動態構建值必須通過的規則。
在我要走的路上,這有可能嗎?如果沒有,那麼指引我走正確道路的幾條指針將不勝感激。
string badValue = "hello!";
const int minSize = 8;
const int maxSize = 30;
Expression<Func<string, bool>> stringLengthMax = value => value.Length < maxSize;
Expression<Func<string, bool>> stringLengthMin = value => value.Length > minSize;
Expression<Func<string, bool>> isEmpty = value => !string.IsNullOrEmpty(value);
BinaryExpression collectAnswers = Expression.And(stringLengthMax.Body, Expression.Invoke(stringLengthMin, stringLengthMax.Parameters));
collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(collectAnswers, stringLengthMax.Parameters));
Func<string, bool> shouldValidate = Expression.Lambda<Func<string, bool>>(collectAnswers, stringLengthMax.Parameters).Compile();
bool result = shouldValidate(badValue);
回答我沒有以正確的方式推進參數,下面是幾個表達式之間共享的多個參數的示例,這些表達式被放入ExpressionTree中並且單個布爾值來自編譯的Func,isValid
const int minSize = 8;
const int maxSize = 30;
Expression<Func<string, int, bool>> stringLengthMax = (value, max) => value.Length <= max;
Expression<Func<string, int, bool>> stringLengthMin = (value, min) => value.Length >= min;
Expression<Func<string, bool>> isEmpty = value => string.IsNullOrEmpty(value);
ParameterExpression valueParameter = Expression.Parameter(typeof(string));
ParameterExpression minParameter = Expression.Parameter(typeof(int));
ParameterExpression maxParameter = Expression.Parameter(typeof(int));
Expression<Func<string, int, int, bool>> minMaxCheck =
Expression.Lambda<Func<string, int, int, bool>>(
Expression.And(Expression.Invoke(stringLengthMax, valueParameter, maxParameter),
Expression.Invoke(stringLengthMin, valueParameter, minParameter)), valueParameter, minParameter, maxParameter);
minMaxCheck = Expression.Lambda<Func<string, int, int, bool>>(
Expression.And(Expression.Invoke(minMaxCheck, valueParameter, minParameter, maxParameter),
Expression.Not(Expression.Invoke(isEmpty, valueParameter))), valueParameter, minParameter, maxParameter);
Func<string, int, int, bool> isValid = minMaxCheck.Compile();
bool resultFalse1 = isValid("hello!", minSize, maxSize); // false - too short
bool resultTrue1 = isValid("hello!", "hello!".Length, maxSize); // true - adjust min
bool resultFalse2 = isValid("1234567890123456789012345678901", minSize, maxSize); // false - too long
bool resultTrue2 = isValid("1234567890123456789012345678901", minSize, "1234567890123456789012345678901".Length); // true - adjust max
bool resultFalse3 = isValid(string.Empty, minSize, maxSize); // false - empty
bool shouldBeTrue = isValid("1234567890", minSize, maxSize); // true - just right
bool resultFalse4 = isValid("1234567890", maxSize, maxSize); // false - adjust min
bool resultFalse5 = isValid("1234567890", minSize, minSize); // false - adjust max
如果你想用Expressions做這個,那麼這樣的東西就行了。雖然你可以建立它,但這並不會造成短路。你非常接近。您需要通過整個參數樹線程化一個參數表達式。
string badValue = "hello!";
const int minSize = 8;
const int maxSize = 30;
Expression<Func<string, bool>> stringLengthMax = value => value.Length < maxSize;
Expression<Func<string, bool>> stringLengthMin = value => value.Length > minSize;
Expression<Func<string, bool>> isEmpty = value => !string.IsNullOrEmpty(value);
ParameterExpression pe = Expression.Parameter(typeof(string));
var x = Expression.Lambda<Func<string, bool>>(
Expression.And(Expression.Invoke(stringLengthMax, pe),
Expression.And(Expression.Invoke(stringLengthMin, pe), Expression.Invoke(isEmpty, pe))), pe);
Func<string, bool> shouldValidate = x.Compile();
bool resultFalse1 = shouldValidate("hello!");
bool resultFalse2 = shouldValidate("1234567890123456789012345678901");
//bool resultFalse3 = shouldValidate(null); Throws an exception because you can't do (null).Length
bool shouldBeTrue = shouldValidate("123456789");
//LinqPad code to view results:
resultFalse1.Dump();
resultFalse2.Dump();
//resultFalse3.Dump();
shouldBeTrue.Dump();
在我看來,你根本不需要構建表達式樹。您可以使用簡單的linq組合您的func(將它們定義為Func<string, bool>
,而不是Expression<Func<string, bool>>
):
Func<string, bool> shouldValidate =
arg => new[] {stringLengthMax, stringLengthMin, isEmpty}.All(func => func(arg));
如果你想使用的不僅僅是and
,你可以邏輯地組合你的func:
Func<string, bool> shouldValidate =
arg => isEmpty(arg) || (stringLengthMax(arg) && stringLengthMin(arg));