如何组合Expression <tdelegate>对象而不调用?

时间:2017-02-25 20:25:15

标签: c# delegates expression expression-trees

我有delegate如下:

public delegate TestResult TestCase(byte[] source);

...返回TestResult的位置如下:

public class TestResult {

    public bool Pass { get; }
    public int Index { get; }

    public TestResult(bool result, int index) {
        Pass = result;
        Index = index;
    }
}

示例TestCase委托如下:

public static TestResult In(byte[] tkn, ITestSet testSet) {
    return testSet.Contains(tkn);
}

ITestSet只不过是封装的HashSet<byte[]>

在一个用例中,我有2个测试集:(1)A - z,(2)0 - 9.我想测试输入byte[]是否在任一测试集中。

我正在使用Expression<TestCase>,但无法弄清楚如何实施Or测试用例。我有一个TestCaseBuilder,其中包含以下方法:

public class TestCaseBuilder {
    private Expression<TestCase> tcExpr;       

    public TestCaseBuilder With(TestCaseBuilder tcBuilder) {
        tcExpr = tcBuilder.tcExpr;
        return this;
    }

    public TestCaseBuilder Or(TestCaseBuilder tcBuilder) {
        tcExpr = tcExpr.Or(tcBuilder.tcExpr);        
        return this;
    }
}

...和我的扩展方法:

public static Expression<TestCase> Or (this Expression<TestCase> tcLeft, Expression<TestCase> tcRight) {
    var lExpr = (LambdaExpression)tcLeft;
    var rExpr = (LambdaExpression)tcRight;    
    var param = lExpr.Parameters;

    return Expression.Lambda<TestCase>(/* what to do here ? */, param);
}

Expression.OrElse机械上是我认为合适但不能使用的,因为我返回的是TestResult,而不是bool

以下是TestCaseBuilder的使用方式:

testcaseBuilder.As("Foo")
    .With(isLetterTestCase)
    .Or(isDigitTestCase);

我仅使用Or代表执行TestCase

public static TestCase Or(this TestCase tc1, TestCase tc2) {
    return tkn => {
        var res = tc1(tkn);
        if (res.Pass) {
            return res;
        }

        return tc2(tkn);
    };
}

如何在不调用第一个测试用例的情况下在自定义Expression<TestCase>方法中合并2 Or

1 个答案:

答案 0 :(得分:0)

这是你想要的吗

        public static Expression<Func<byte[], TestResult, TestCase, TestResult>> helperExp = (inp, res, next) => res.Pass ? next(inp) : res;

        public static Expression<TestCase> Or(Expression<TestCase> exp1, Expression<TestCase> exp2)
        {
            var param = exp1.Parameters;

            Expression<TestCase> or = Expression.Lambda<TestCase>(
               Expression.Invoke(helperExp,
                param[0], Expression.Invoke(exp1, param), exp2),param);

            return or;
        }

使用块表达式无需调用

public static Expression<TestCase> Or(Expression<TestCase> exp1, Expression<TestCase> exp2)
        {
            var param = exp1.Parameters;

            ParameterExpression local = Expression.Parameter(typeof(TestResult), "local");

            BlockExpression block = Expression.Block(
                new[] { local },
                Expression.Assign(local, exp1.Body),
                Expression.Condition(Expression.Property(local, nameof(TestResult.Pass)), exp2.Body, local));

            return Expression.Lambda<TestCase>(block, param);
        }

测试

            Expression<TestCase> exp1 = (tc) => new TestResult(true);
            Expression<TestCase> exp2 = (tc) => new TestResult(false);

            var first = Or(exp1, exp1);

            var second = Or(first, exp2);

            var func = second.Compile();

            var result = func(new byte[] { });

使用https://github.com/louthy/csharp-monad可能有更好的方法来执行没有表达式的条件monad 我的.net核心使用monad原则用于中间件。