2017-02-25 42 views
0

我有一個delegate如下:如何結合表達式<TDelegate>對象沒有調用?

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[]>多得多。在一個用例中,我有兩個測試集:(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用於:

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>無:

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

我也只用TestCase代表進行Or調用第一個測試用例?

+0

我想你需要一個自定義的ExpressionVisitor,它提供了參數來訪問這兩個表達式,返回一個新的返回一個新的 – pinkfloydx33

+0

@ pinkfloydx33:可能很好......我還沒有使用ExpressionVisitor,有人將能夠提供一個解決方案。這個*測試案例*僅僅是冰山一角。 – IAbstract

+0

寫一個很容易。我一直在用手機,所以很難寫出一個。如果您搜索ParameterReplacer或ExpressionParamaterReplacer,則會顯示一條Marc Gravell的帖子顯示使用情況。 – pinkfloydx33

回答

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 我的東西.net核心使用monad中間件原理。

+0

如果沒有'Expression.Invoke'是必需的。 – IAbstract

+1

@IAbstract但是如果你在某個時間點沒有進行調用,你怎麼能知道結果呢? –

+1

@IAbstract做了一個編輯來刪除調用,如果它仍然不是你想要的留下評論,我會刪除答案。 –

相關問題