2011-06-07 13 views
7

क्या मैं कहना है कि InvokeMethod एक विधि आह्वान कर सकते हैं और जब दोहराएँ जैसे विशेष विकल्पों का उपयोग कर यह दोहराएँ के बाद exexute करेगा मुझे क्या करना होगा के लिए सी # बिल्डिंग Fluent एपीआई।विधि आमंत्रण

अब मेरी समस्या यह है कि विधि पहले से ही निष्पादित होगी इससे पहले कि यह जानता है कि इसे 100 बार कहा जाना है।

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 (एक्शन एक्शन, int repeat = 1) – Hath

+0

जैसे invokemethod के तर्क के रूप में 'दोहराना' क्यों नहीं है मैंने इसके बारे में भी सोचा, लेकिन मुझे यह पसंद नहीं है, क्योंकि आप नहीं देख सकते कि संख्या क्या है पैरामीटर नाम पढ़ने के बिना। – Rookian

+0

आप कॉल करते समय अधिक स्पष्ट होने के लिए नामित पैरामीटर का उपयोग कर सकते हैं। –

उत्तर

2

इस बिल्ली त्वचा के लिए तरीके का एक बहुत हैं, लेकिन मुझे लगता है कि इस कठिनाई का एक स्रोत तथ्य यह है कि आप वास्तव में InvokeMethod() विधि के भीतर विधि आह्वान में है (आंकड़ा जाना!)।

आमतौर पर, हम सिंटैक्स को चालू करने के लिए धाराप्रवाह एपीआई का उपयोग करते हैं, जिसे अंदरूनी से मूल्यांकन किया जाता है जिसे बाएं से दाएं फैशन में व्यक्त किया जा सकता है। इस प्रकार, इंटरफ़ेस के अभिव्यक्ति निर्माता घटक का उपयोग पूरे अभिव्यक्ति में राज्य बनाने के लिए किया जाता है, और केवल अंत में "वास्तविक कार्य" होता है। अपने तत्काल समस्या का

एक समाधान उसके संबंधित विकल्प (मंगलाचरण की स्थिति, दोहराने गिनती, आदि) के साथ एक कार्रवाई को कतार, और MethodExecuter कि dequeues करने के लिए कुछ ExecuteAll() विधि जोड़ने के लिए है और के अंत में पूरी तरह से कॉन्फ़िगर किया गया कार्यों को निष्पादित करता है सदस्य श्रृंखला

एक और समाधान 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; 
} 

मैं दृश्य स्टूडियो में इस के माध्यम से काम नहीं किया है, लेकिन अन्य मदों की तरह कुछ होगा:

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; } 
} 

ध्यान दें कि RepeatCount और Action इंटरफ़ेस पर प्रकट नहीं किए गए हैं। इस तरह, आप .Invoke(x => x. पर कॉल करते समय इन सदस्यों को नहीं देख पाएंगे, लेकिन Invoke() विधि के अंदर कंक्रीट ExecutionBuilder कक्षा का उपयोग करते समय उन्हें पहुंच होगी।

3

आप क्या प्रदान की है एक कार्यप्रवाह या राज्य मशीन प्रोग्रामिंग की तरह एक सा लग रहा है। निष्पादन के दौरान आमंत्रण और सम्मान की स्थिति को पकड़ने के लिए, आपको अपना दृष्टिकोण थोड़ा बदलना होगा।

जैसे ही वे आते हैं, कार्यों को आविष्कार करने के बजाय, अपने कार्यों को कतार में धक्का देने और फिर राज्य मशीन चलाने के लिए एक तंत्र प्रदान करने पर विचार करें।

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

शायद एक स्टैक के बजाय एक कतार है। – Jay

+0

हाँ, एक कतार शायद एक बेहतर दृष्टिकोण है। पोस्ट अपडेट कर रहा है। – bryanbcook

+0

मैंने मुझे जेज़ समाधान के लिए निर्णय लिया, क्योंकि यह अन्य सभी समाधानों की तुलना में बोलने में अधिक धाराप्रवाह या अधिक प्राकृतिक है। किसी भी तरह से आपके सुझाव के लिए धन्यवाद :) – Rookian

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

आप एक SetInvokeMethod और एक Execute विधि हो सकता था।

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(); 
    } 
} 
संबंधित मुद्दे