3

(答えは下に向かって)

を組み合わせたシステムを構築しようとしています。

Func<T, bool> 

これにより、値 (この場合は badValue) を渡して、述語がすべて true を返し、二項演算が考慮される場合に bool を取得できます。Expression/ExpressionTrees を使用するのはこれが初めてなので、お手柔らかにお願いします。

次のエラーが表示されます。

ArgumentException: タイプ 'System.Boolean' の式を呼び出せません

この行で:

collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(...

valueすべてのエクスプレッション間で参照を共有する必要があるため、その行をそのように設定しました(そうですか?)。

私の理想的なシナリオは、たくさんあることです

Expression<Func<blah, blah, bool>> 

これらを論理演算子 (And/Or/Not) と一緒にシステムに渡し、最後にブール値を取得できます。値が通過しなければならないルールの動的な構築を可能にすることを望んでいます。

私が行くルートでもそれは可能ですか?そうでない場合は、私を正しい道に導くいくつかの指針をいただければ幸いです。

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 に配置された複数の Expression 間で共有される複数のパラメーターの例であり、コンパイルされた 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
4

2 に答える 2

4

Expressions でそれを行いたい場合は、このようなものが機能します。あなたはそれを組み込むことができますが、これはショートサーキットではありません.あなたはかなり近かった. パラメーター ツリー全体で 1 つのパラメーター式をスレッド化する必要があります。

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();
于 2013-05-23T17:30:34.407 に答える
1

式ツリーを作成する必要はまったくないように思えます。単純な linq を使用して funcs を組み合わせることができます ( ではFunc<string, bool>なくとして定義しますExpression<Func<string, bool>>)。

Func<string, bool> shouldValidate = 
    arg => new[] {stringLengthMax, stringLengthMin, isEmpty}.All(func => func(arg));

以外のものを使用したい場合andは、 funcs を論理的に組み合わせることができます。

Func<string, bool> shouldValidate = 
    arg => isEmpty(arg) || (stringLengthMax(arg) && stringLengthMin(arg));
于 2013-05-23T02:25:02.980 に答える