2011-06-07 52 views
7

我有什麼做的,說的InvokeMethod可以調用方法,並利用特殊的選項,如重複時,應當在重複後exexute C#樓流利的API。方法調用

我現在的問題是該方法在它知道必須被調用100次之前已經執行了exexute。

class Program 
{ 
    static void Main() 
    { 
     const bool shouldRun = true; 

     new MethodExecuter() 
      .ForAllInvocationsUseCondition(!Context.WannaShutDown) 
       .InvokeMethod(A.Process).Repeat(100) 
       .When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10) 
      .ForAllInvocationsUseCondition(Context.WannaShutDown) 
       .When(shouldRun).ThenInvokeMethod(C.Process); 
    } 
} 

MethodExpression的

public class MethodExpression 
{ 
    private bool _isTrue = true; 
    private readonly MethodExecuter _methodExecuter; 
    public MethodExpression(bool isTrue, MethodExecuter methodExecuter) 
    { 
     _isTrue = isTrue; 
     _methodExecuter = methodExecuter; 
    } 

    public MethodExecuter ThenInvokeMethod(Action action) 
    { 
     if (_isTrue) 
     { 
      action.Invoke(); 
      _isTrue = false; 
     } 
     return _methodExecuter; 
    } 
} 

MethodExecuter

public class MethodExecuter 
{ 
    private bool _condition; 
    private int _repeat = 1; 

    public MethodExpression When(bool isTrue) 
    { 
     return new MethodExpression(isTrue && _condition, this); 
    } 

    public MethodExecuter InvokeMethod(Action action) 
    { 
     if (_condition) 
     { 
      for (int i = 1; i <= _repeat; i++) 
      { 
       action.Invoke(); 
      } 
     } 
     return this; 
    } 

    public MethodExecuter ForAllInvocationsUseCondition(bool condition) 
    { 
     _condition = condition; 
     return this; 
    } 

    public MethodExecuter Repeat(int repeat) 
    { 
     _repeat = repeat; 
     return this; 
    } 
} 
+0

爲什麼不能有「重複」作爲的InvokeMethod像的InvokeMethod參數(行動行動,整合重複= 1) – Hath 2011-06-07 16:44:57

+0

我想過太多,但我不喜歡它,因爲你不能看到什麼是多少因爲沒有讀取參數名稱。 – Rookian 2011-06-07 16:48:31

+0

您可以在調用命名參數時使用更明確的參數。 – 2011-06-07 16:53:25

回答

2

有很多方法對皮膚這隻貓,但是我覺得這個困難的一個來源是事實,你實際調用InvokeMethod()方法中的方法(去圖!)。

通常,我們使用流暢的API將從內向外評估的語法轉化爲可以以從左到右的方式表達的語法。因此,接口的表達式構建器組件被用來在整個表達式中建立狀態,並且只在最後才發生「真正的工作」。

一個解決方案是你的直接問題就是排隊,與其相關的選項(調用條件,重複計數等)的每一個動作,並添加一些ExecuteAll()方法MethodExecuter該出隊,並在年底執行完全配置的操作會員鏈。

另一種解決方案是將所有執行選項放在InvokeMethod()方法中;是這樣的:

.Invoke(x => x.Method(A.Process).Repeat(100)) 

這種方法看起來是這樣的:

public MethodExecuter Invoke(Action<IExecutionBuilder> executionBuilder) 
{ 
    var builder = new ExecutionBuilder(); 
     executionBuilder(builder); 

     var action = builder.Action; 
     var repeat = builder.RepeatCount; 

     if (_condition) 
     { 
      for (int i = 1; i <= repeat; i++) 
      { 
       action(); 
      } 
     } 

     return this; 
} 

我沒有在Visual Studio通過這個工作,但其他項目會是這樣的:

public interface IExecutionBuilder 
{ 
    IExecutionBuilder Method(Action action); 
     IExecutionBuilder Repeat(int count); 
} 

public class ExecutionBuilder : IExecutionBuilder 
{ 
     public ExecutionBuilder() 
     { 
      RepeatCount = 1; // default to repeat once 
      Action =() => {}; // default to do nothing, but not null 
     } 

    public IExecutionBuilder Method(Action action) 
     { 
      Action = action; 
      return this; 
     } 

     public IExecutionBuilder Repeat(int repeat) 
     { 
      RepeatCount = repeat; 
        return this; 
     } 

     public int RepeatCount { get; private set; } 
     public Action Action { get; private set; } 
} 

請注意,RepeatCountAction未在接口上公開。這樣,您在致電.Invoke(x => x.時不會看到這些成員,但在使用Invoke()方法中的具體ExecutionBuilder類時可以訪問這些成員。

3

您提供什麼樣子有點像編程工作流程或狀態機。爲了在執行過程中捕捉調用和尊重條件,您需要稍微改變您的方法。

不要在進入時調用動作,而應考慮將動作推入隊列中,然後提供運行狀態機的機制。

new MethodInvoker() 
     .ForAllInvocationsUseCondition(true) 
      .InvokeMethod(Process.A).Repeat(100) 
     .Run(); 
+1

可能是一個隊列,而不是堆棧。 – Jay 2011-06-07 17:12:04

+0

是的,隊列可能是更好的方法。更新帖子。 – bryanbcook 2011-06-08 16:28:04

+0

我決定爲Jays解決方案,因爲它比所有其他解決方案更流暢或更自然。無論如何謝謝你的建議:) – Rookian 2011-06-08 20:59:36

3

使用最後一個方法(「走出去」,或「執行」)實際踢東西了。

 new MethodExecuter() 
     .ForAllInvocationsUseCondition(!Context.WannaShutDown) 
      .InvokeMethod(A.Process).Repeat(100) 
      .When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10) 
     .ForAllInvocationsUseCondition(Context.WannaShutDown) 
      .When(shouldRun).ThenInvokeMethod(C.Process) 
      .Go(); 
1

你可以有一個SetInvokeMethodExecute方法。

SetInvokeMethod(Action).Repeat(100).Execute() 
0

句子中,你的代碼太「熱切」了。 InvokeMethod方法被調用,並且在流利的語法結構告訴您的代碼應該重複多少次之前執行該操作。

要改變這種情況,請嘗試在您的methodInvoker中指定您作爲私有字段調用的方法,然後包含一個命令,該命令是實際執行命令的「觸發器」。關鍵是「懶惰評估」;在一個流暢的界面中,除非必要,否則不應該做任何事情;這樣,當你發生這種情況時,你可以掌握大部分的控制權。

public class FluentMethodInvoker 
{ 
    Predicate condition =()=>true; 
    Predicate allCondition = null; 
    Action method =()=> {return;}; 
    bool iterations = 1; 
    FluentMethodInvoker previous = null; 

    public FluentMethodInvoker(){} 
    private FluentMethodInvoker(FluentMethodInvoker prevNode) 
    { previous = prevNode; } 

    public FluentMethodInvoker InvokeMethod(Action action) 
    { 
     method = action; 
    } 

    //Changed "When" to "If"; the function does not wait for the condition to be true 
    public FluentMethodInvoker If(Predicate pred) 
    { 
     condition = pred; 
     return this; 
    } 

    public FluentMethodInvoker ForAllIf(Predicate pred) 
    { 
     allCondition = pred; 
     return this; 
    } 

    private bool CheckAllIf() 
    { 
     return allCondition == null 
       ? previous == null 
        ? true 
        : previous.CheckAllIf(); 
       : allCondition; 
    } 

    public FluentMethodInvoker Repeat(int repetitions) 
    { 
     iterations = repetitions; 
     return this; 
    } 

    //Merging MethodExecuter and MethodExpression, by chaining instances of FluentMethodInvoker 
    public FluentMethodInvoker Then() 
    { 
     return new FluentMethodInvoker(this); 
    } 

    //Here's your trigger 
    public void Run() 
    { 
     //goes backward through the chain to the starting node 
     if(previous != null) previous.Run(); 

     if(condition && CheckAllIf())  
      for(var i=0; i<repetitions; i++) 
       method(); 

     return; 
    } 
} 

//usage 
class Program 
{ 
    static void Main() 
    { 
     const bool shouldRun = true; 

     var invokerChain = new FluentMethodInvoker() 
      .ForAllIf(!Context.WannaShutDown) 
       .InvokeMethod(A.Process).Repeat(100) 
       .When(shouldRun) 
      .Then().InvokeMethod(B.Process).Repeat(10) 
      .ForAllIf(Context.WannaShutDown) 
       .When(shouldRun) 
      .Then().InvokeMethod(C.Process); 

     //to illustrate that the chain doesn't have to execute immediately when being built 
     invokerChain.Run(); 
    } 
}