如何在<TDelegate>不调用的情况下组合表达式对象?



我的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);

我仅使用TestCase代表进行了Or

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

如何在自定义Or方法中组合2个Expression<TestCase>,而无需调用第一个测试案例?

这是您想要的

        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,可能有更好的方法来进行有条件的单元,而无需表达我的东西.NET Core将中间件的单调原理使用。

相关内容

最新更新