2010-09-20 17 views
13

के बाद कार्रवाई अमल मैं एक खिड़कियों सांत्वना आवेदन जो एक कार्रवाई समय-समय पर एक निश्चित समय के बाद निष्पादित करता है विकसित करना चाहते हैं। मैंने कहीं पढ़ा है कि एक टाइमर क्लास केवल विंडोज़ फॉर्म अनुप्रयोगों के लिए उपलब्ध है, तो मैं जो चाहता हूं उसे पूरा करने का सबसे अच्छा तरीका क्या है?सी # X सेकंड

उत्तर

15

आप कंसोल एप्लिकेशन में System.Threading.Timer (या वैकल्पिक रूप से System.Timers.Timer, जो प्रभावी रूप से सिस्टम के रूप में समान है। थ्रेडिंग टिमर) का उपयोग कर सकते हैं। यह केवल विंडोज फॉर्म या डब्ल्यूपीएफ विशिष्ट टाइमर है जिन्हें आप टालना चाहते हैं।

5

Rx का उपयोग करके आप यह कर सकते हैं:

 var timer = Observable.Interval(TimeSpan.FromSeconds(1)); 
     timer.Subscribe(l => Console.WriteLine(l)); 
     Thread.Sleep(Timeout.Infinite); 

बस एक और विकल्प।

20

मूल संदेश: मैंने यह नमूना कंसोल एप्लिकेशन लिखा है (सी # 4.0 [डिफ़ॉल्ट पैरामीटर द्वारा इंगित अनुसार] का उपयोग करके)। यह बेहद बहुमुखी है और एक्शन प्रतिनिधि स्निपेट को पास करने की अनुमति देने के लिए प्रतिनिधि है जिसे आप टाइमर कक्षा ( सिस्टम। थ्रेडिंग) में उपयोग करके निष्पादित करना चाहते हैं। अतिभारित Doकी विधि स्थिर वर्ग में देरी के अंतराल कंप्यूटिंग के सभी शेष काम करता है। आप वैकल्पिक रूप से एक अंतराल निर्दिष्ट करके दोहराया जा सकता है ( मिलीसेकंड में)। आप बार-बार अंतराल के लिए टाइमस्पेन को स्वीकार करने के तरीके को संशोधित कर सकते हैं।

तीन साल पहले प्रदान किया गया कंसोल एप्लिकेशन उदाहरण इस प्रकृति के कुछ लोगों की तलाश में लोगों के लिए बहुत लोकप्रिय साबित हुआ है। कई प्रश्नों ने नौकरी अनुसूची प्रबंधन के साथ निपटाया। मैंने एक नई कक्षा लिखने में एक दरार ली जिसे काफी सरलता से लागू किया जा सकता है। यह केवल उपयोग के उदाहरण के रूप में प्रदान किया जाता है। जो लोग मानते हैं कि मेरी शैली कम है या अनावश्यक कोड के साथ झुका हुआ है, यह मेरे द्वारा ठीक है। यह अपने प्रोग्रामिंग शैली, कार्यान्वयन प्रथाओं, आदि के लिए यह बदलाव करने आप पर निर्भर है

वर्ग में निम्न परिवर्तन इसे और अधिक उपयोगी बनाने:

  • Do() के साथ रोजगार के अवसर बनाना विधि इसी तरह काम करता है पुरानी कक्षा के रूप में। एक अतिरिक्त वैकल्पिक पैरामीटर कुंजी (प्रकार वस्तु) तुम्हें नौकरी का नाम निर्दिष्ट करने देने के लिए प्रदान की गई है। यह नाम आपको पूर्व निर्धारित नौकरियों को संशोधित करने देगा (पढ़ना जारी रखें)।
  • तत्काल टाइमर ऑब्जेक्ट्स को कक्षा में आंतरिक रूप से रखा जाता है ताकि आपको कई अनुसूचित कार्यों की अनुमति मिल सके जिन्हें व्यक्तिगत रूप से संदर्भित किया जा सके।
  • नौकरी प्रबंधन (कुंजी का उपयोग करके) के लिए नए हैंडलर जोड़े गए हैं। वे GetJobFor(), EndJob(), और ResumeJob तरीकों से SuspendJob() प्रदान की जाती हैं।
  • स्टेटिक कन्स्ट्रक्टर AppDomain.CurrentDomain.DomainUnload "deconstructor" के लिए किसी भी चलती नौकरियों का निपटान करने के लिए ऐपडोमेन (एप्लिकेशन) अनलोडिंग होने पर ईवेंट की सदस्यता लेता है।
  • पैरामीटर जाँच यकीन है कि मापदंड हैं क्या उम्मीद है बनाने के लिए जोड़ा गया है।
  • Scoped लॉकिंग आप किसी भी धागे से नौकरियों को जोड़ने के लिए अनुमति देता है।

क्या नहीं बदला है?

  • उदाहरण अभी भी कार्रवाई प्रतिनिधि का परिणाम संभाल नहीं करता है। अगर आपको कुछ बेहतर चाहिए, तो इसे लागू करें। :)

कक्षा के नए कार्यान्वयन को खोजने के लिए नीचे स्क्रॉल करें। का आनंद लें!


** पुराने सांत्वना वर्ग इस प्रकार है: **

using System; 
    using System.Threading; 

    namespace ConsoleApplication1 
    { 
    /// <summary> 
    /// Class that manages the execution of tasks sometime in the future. 
    /// </summary> 
    public static class At 
    { 
    #region Members 

    /// <summary> 
    /// Specifies the method that will be fired to execute the delayed anonymous method. 
    /// </summary> 
    private readonly static TimerCallback timer = new TimerCallback(At.ExecuteDelayedAction); 

    #endregion 

    #region Methods 

    /// <summary> 
    /// Method that executes an anonymous method after a delay period. 
    /// </summary> 
    /// <param name="action">The anonymous method that needs to be executed.</param> 
    /// <param name="delay">The period of delay to wait before executing.</param> 
    /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param> 
    public static void Do(Action action, TimeSpan delay, int interval = Timeout.Infinite) 
    { 
     // create a new thread timer to execute the method after the delay 
     new Timer(timer, action, Convert.ToInt32(delay.TotalMilliseconds), interval); 

     return; 
    } 

    /// <summary> 
    /// Method that executes an anonymous method after a delay period. 
    /// </summary> 
    /// <param name="action">The anonymous method that needs to be executed.</param> 
    /// <param name="delay">The period of delay (in milliseconds) to wait before executing.</param> 
    /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param> 
    public static void Do(Action action, int delay, int interval = Timeout.Infinite) 
    { 
     Do(action, TimeSpan.FromMilliseconds(delay), interval); 

     return; 
    } 

    /// <summary> 
    /// Method that executes an anonymous method after a delay period. 
    /// </summary> 
    /// <param name="action">The anonymous method that needs to be executed.</param> 
    /// <param name="dueTime">The due time when this method needs to be executed.</param> 
    /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param> 
    public static void Do(Action action, DateTime dueTime, int interval = Timeout.Infinite) 
    { 
     if (dueTime < DateTime.Now) 
     { 
      throw new ArgumentOutOfRangeException("dueTime", "The specified due time has already elapsed."); 
     } 

     Do(action, dueTime - DateTime.Now, interval); 

     return; 
    } 

    /// <summary> 
    /// Method that executes a delayed action after a specific interval. 
    /// </summary> 
    /// <param name="o">The Action delegate that is to be executed.</param> 
    /// <remarks>This method is invoked on its own thread.</remarks> 
    private static void ExecuteDelayedAction(object o) 
    { 
     // invoke the anonymous method 
     (o as Action).Invoke(); 

     return; 
    } 

    #endregion 
    } 

    class Program 
    { 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Time: {0} - started", DateTime.Now); 

     // demonstrate that order is irrelevant 
     At.Do(() => Console.WriteLine("Time: {0} - Hello World! (after 5s)", DateTime.Now), DateTime.Now.AddSeconds(5)); 
     At.Do(() => Console.WriteLine("Time: {0} - Hello World! (after 3s)", DateTime.Now), DateTime.Now.AddSeconds(3)); 
     At.Do(() => Console.WriteLine("Time: {0} - Hello World! (after 1s)", DateTime.Now), DateTime.Now.AddSeconds(1)); 

     At.Do 
     (
      () => 
      { 
       // demonstrate flexibility of anonymous methods 
       for (int i = 0; i < 10; i++) 
       { 
       Console.WriteLine("Time: {0} - Hello World! - i == {1} (after 4s)", DateTime.Now, i); 
       } 
      }, 
      TimeSpan.FromSeconds(4) 
     ); 

     // block main thread to show execution of background threads 
     Thread.Sleep(100000); 

     return; 
    } 
    } 
    } 

** नया वर्ग प्रदान की जाती है इस प्रकार है: **

using System; 
using System.Linq; 
using System.Threading; 
using System.Collections.Generic; 

namespace Utility 
{ 
    /// <summary> 
    /// Class that is designed to execution Action-based anonymous delegates after a specified 
    /// interval. This class also supports repetitive tasks on an interval. 
    /// </summary> 
    public static class At 
    { 
     #region Embedded Classes 

     /// <summary> 
     /// Embedded class definition for common At job periods. 
     /// </summary> 
     public static class Periods 
     { 
     #region Members 

     /// <summary> 
     /// Specifies an object that indicates to not restart. 
     /// </summary> 
     public static readonly TimeSpan DoNotStart = TimeSpan.FromMilliseconds(-1.0); 

     /// <summary> 
     /// Specifies an object that indicates to start immediately. 
     /// </summary> 
     public static readonly TimeSpan Immediately = TimeSpan.FromMilliseconds(0.0); 

     /// <summary> 
     /// Specifies an interval of one second. 
     /// </summary> 
     public static readonly TimeSpan SecondsOne = TimeSpan.FromSeconds(1.0); 

     /// <summary> 
     /// Specifies an interval of five seconds. 
     /// </summary> 
     public static readonly TimeSpan SecondsFive = TimeSpan.FromSeconds(5.0); 

     /// <summary> 
     /// Specifies an interval of fifteen seconds. 
     /// </summary> 
     public static readonly TimeSpan SecondsFifteen = TimeSpan.FromSeconds(15.0); 

     /// <summary> 
     /// Specifies an interval of thirty seconds. 
     /// </summary> 
     public static readonly TimeSpan SecondsThirty = TimeSpan.FromSeconds(30.0); 

     /// <summary> 
     /// Specifies an interval of 100ms. 
     /// </summary> 
     public static readonly TimeSpan MicroDelay = TimeSpan.FromMilliseconds(100); 

     #endregion 
     } 

     #endregion 

     #region Members 

     /// <summary> 
     /// Specifies an object that can be used for synchronization. 
     /// </summary> 
     private readonly static object syncRoot; 

     /// <summary> 
     /// Specifies a collection of Timer object that were created for interval-based execution. 
     /// </summary> 
     /// <remarks> 
     /// We must keep these in a collection to prevent the GC from disposing of the timers. 
     /// </remarks> 
     private readonly static Dictionary<object, Timer> ActiveTimers; 

     /// <summary> 
     /// Specifies a collection of timestamps of when timers are created. 
     /// </summary> 
     private readonly static Dictionary<object, DateTime> TimerCreation; 

     /// <summary> 
     /// Specifies an object that will produce pseudo-random numbers. 
     /// </summary> 
     private readonly static Random RNG; 

     #endregion 

     #region Static Constructor 

     static At() 
     { 
     syncRoot = new object(); 

     ActiveTimers = new Dictionary<object, Timer>(); 
     TimerCreation = new Dictionary<object, DateTime>(); 

     RNG = new Random(); 

     // "deconstructor" 
     AppDomain.CurrentDomain.DomainUnload += new EventHandler(CurrentDomain_DomainUnload); 

     return; 
     } 

     /// <summary> 
     /// Method used to cleanup resources used by this object. 
     /// </summary> 
     static void CurrentDomain_DomainUnload(object sender, EventArgs e) 
     { 
     // dispose of all the timers directly 
     At.ActiveTimers.Values.ToList().ForEach(a => a.Dispose()); 

     return; 
     } 

     #endregion 

     #region Methods 

     #region At Job Staging 

     /// <summary> 
     /// Method that executes an anonymous method after a delay period. 
     /// </summary> 
     /// <param name="action">The anonymous method that needs to be executed.</param> 
     /// <param name="delay">The period of delay to wait before executing.</param> 
     /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param> 
     public static Timer Do(Action action, TimeSpan delay, TimeSpan? onInterval = null, object key = null) 
     { 
     Timer timer; 

     if (key == null) 
     { 
      // auto-generate a key 
      key = string.Concat("Auto(", At.RNG.NextNonNegativeLong(), ")"); 
     } 

     lock (At.ActiveTimers) 
     { 
      // action - contains the method that we wish to invoke 
      At.ActiveTimers.Add(key, timer = new Timer(ActionInvoker, action, delay, onInterval ?? At.Periods.DoNotStart)); 
      At.TimerCreation.Add(key, DateTime.Now); 
     } 

     //Log.Message 
     //(
     // LogMessageType.Debug, 
     // "[DEBUG] {0}: registered At job (key = {1}, initial delay = {2}, interval = {3})", 
     // action, 
     // key, 
     // delay, 
     // (onInterval == null) ? "never" : onInterval.Value.ToString() 
     //); 

     return timer; 
     } 

     /// <summary> 
     /// Method that executes an anonymous method after a delay period. 
     /// </summary> 
     /// <param name="action">The anonymous method that needs to be executed.</param> 
     /// <param name="delay">The period of delay (in milliseconds) to wait before executing.</param> 
     /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param> 
     public static Timer Do(Action action, int delay, int interval = Timeout.Infinite, object key = null) 
     { 
     return Do(action, TimeSpan.FromMilliseconds(delay), TimeSpan.FromMilliseconds(interval), key); 
     } 

     /// <summary> 
     /// Method that executes an anonymous method after a delay period. 
     /// </summary> 
     /// <param name="action">The anonymous method that needs to be executed.</param> 
     /// <param name="dueTime">The due time when this method needs to be executed.</param> 
     /// <param name="interval">The period (in milliseconds) to delay before executing the anonymous method again (Timeout.Infinite to disable).</param> 
     public static Timer Do(Action action, DateTime dueTime, int interval = Timeout.Infinite, object key = null) 
     { 
     if (dueTime < DateTime.Now) 
     { 
      throw new ArgumentOutOfRangeException("dueTime", "The specified due time has already elapsed."); 
     } 

     return Do(action, dueTime - DateTime.Now, TimeSpan.FromMilliseconds(interval), key); 
     } 

     #endregion 

     #region At Job Retrieval 

     /// <summary> 
     /// Method that attempts to retrieve a job (Timer object) for a given key. 
     /// </summary> 
     /// <param name="key">The key that we are getting a job for.</param> 
     public static Timer GetJobFor(object key) 
     { 
     if (key == null) 
     { 
      throw new ArgumentNullException("key"); 
     } 

     lock (At.ActiveTimers) 
     { 
      if (At.ActiveTimers.ContainsKey(key) == false) 
      { 
       /* 
       Log.Message 
       (
        LogMessageType.Error, 
        "[ERROR] At({0}): unable to find a job with specified key", 
        key 
       ); 
       */ 
       return null; 
      } 

      return At.ActiveTimers[key]; 
     } 
     } 

     /// <summary> 
     /// Method that ends a job and removes all resources associated with it. 
     /// </summary> 
     /// <param name="key">The key that we are getting a job for.</param> 
     public static void EndJob(object key) 
     { 
     Timer timer; 

     if ((timer = GetJobFor(key)) == null) 
     { 
      // no timer - cannot suspend 
      return; 
     } 

     // dispose of the timer object 
     timer.Dispose(); 

     lock (At.ActiveTimers) 
     { 
      // remove the existence from the dictionary 
      At.ActiveTimers.Remove(key); 
      /* 
      Log.Message 
      (
       LogMessageType.Info, 
       "[INFO] At({0}): job has been disposed (created {1}, duration {2})", 
       key, 
       TimerCreation[key].ToISODateTime(), 
       (DateTime.Now - TimerCreation[key]).ToText() 
      ); 
      */ 
      At.TimerCreation.Remove(key); 
     } 

     return; 
     } 

     /// <summary> 
     /// Method that attempts to suspend an active job (using the provided key). 
     /// </summary> 
     /// <param name="key">The key that we are getting a job for.</param> 
     public static void SuspendJob(object key) 
     { 
     Timer timer; 

     if ((timer = GetJobFor(key)) == null) 
     { 
      // no timer - cannot suspend 
      return; 
     } 

     // set the timer to not restart 
     timer.Change(TimeSpan.FromMilliseconds(-1), TimeSpan.FromMilliseconds(-1)); 
     /* 
     Log.Message 
     (
      LogMessageType.Info, 
      "[INFO] At({0}): job has been suspended", 
      key 
     ); 
     */ 
     return; 
     } 

     /// <summary> 
     /// Method that attempts to resume an active job (using the provided key). 
     /// </summary> 
     /// <param name="key">The key that we are getting a job for.</param> 
     /// <param name="delay">The amount of delay before restarting the job (specify <b>0</b> to restart immediately).</param> 
     /// <param name="interval">The delay between intervals (specify <b>-1ms</b> to prevent intervals).</param> 
     public static void ResumeJob(object key, TimeSpan delay, TimeSpan interval) 
     { 
     Timer timer; 

     if ((timer = GetJobFor(key)) == null) 
     { 
      // no timer - cannot suspend 
      return; 
     } 

     // set the timer to not restart 
     timer.Change(delay, interval); 
     /* 
     Log.Message 
     (
      LogMessageType.Info, 
      "[INFO] At({0}): job has been resumed (delay = {1}, interval = {2})", 
      key, 
      delay, 
      interval 
     ); 
     */ 
     return; 
     } 

     #endregion 

     /// <summary> 
     /// Method that invokes an action delegate on a timer. 
     /// </summary> 
     /// <param name="o">A reference to the action that is to be taken.</param> 
     private static void ActionInvoker(object o) 
     { 
     // invoke the delegate 
     (o as Action).Invoke(); 

     return; 
     } 

     #endregion 
    } 
} 
+1

नरक! यह और पसंद होना चाहिए! –

+1

यह अपने उद्देश्य को पूरा करेगा, लेकिन मैं इस रूप में उत्पादन कोड में इसका इस्तेमाल नहीं होगा: पहले, आप अपने टाइमर निपटान नहीं कर रहे हैं, जिसका अर्थ है वे अपनी मूल टाइमर द्वारा जीवित रखा जाता है, निपटान और उन्हें एकत्र करने से जी सी को रोकने। हर बार जब आप 'Do' विधि को कॉल करते हैं तो आप एक नया अनावश्यक उदाहरण बना रहे हैं। अन्य मुद्दों अच्छा प्रोग्रामिंग प्रथाओं से अधिक संबंधित: आप एक खाली 'return' साथ प्रत्येक विधि समाप्त करने के लिए नहीं है,' ExecuteDelayedAction' नहीं एक 'object' एक पैरामीटर के रूप में लेना चाहिए कास्टिंग से बचने के लिए, और' timer' एक सा है कुछ ऐसा करने के लिए खराब नामकरण विकल्प जो वास्तव में टाइमर नहीं है। – Groo

+0

मैं टाइमर का निपटान कैसे कर सकता हूं? क्या आप इस समस्या को हल करने के लिए इस कोड को संशोधित कर सकते हैं? –

3
//<Namespace>.Utilities.Extensions 
public static class ActionExtensions 
{ 
    public static void RunAfter(this Action action, TimeSpan span) 
    { 
     var dispatcherTimer = new DispatcherTimer { Interval = span }; 
     dispatcherTimer.Tick += (sender, args) => 
     { 
      var timer = sender as DispatcherTimer; 
      if (timer != null) 
      { 
       timer.Stop(); 
      } 

      action(); 
     }; 
     dispatcherTimer.Start(); 
    } 
} 

//<Namespace>.Utilities 
public static class CommonUtil 
{ 
    public static void Run(Action action, TimeSpan afterSpan) 
    { 
     action.RunAfter(afterSpan); 
    } 
} 

उपयोग:

CommonUtil.Run(() => 
{ 
    // some actions 
}, TimeSpan.FromMilliseconds(5000)); 
+0

'डिस्पैचर टिमर' को 'System.Windows.Forms.Timer' के साथ प्रतिस्थापित किया जा सकता है और यह WinForms में काम करता है। –

0

कुछ समय-समय पर करने के लिए सबसे आसान तरीका यह

new Timer((Object stateInfo) => { Console.WriteLine("Your Job every 1 sec"); }, new AutoResetEvent(false), 0, 1000); 

की तरह उपयोग कोड आप एक देरी (एक्स सेकंड के बाद कार्रवाई अमल) परिवर्तन 0 मिलीसेकंड की संख्या के अनुसार बनाने के लिए चाहते हैं, तो है।

आप केवल देरी, Timeout.Infinite 1000 को बदलने की जरूरत है।

बेशक

, आप धागा ब्लॉक करने के लिए है:

Console.ReadKey(); 

या

autoEvent.WaitOne() 

अगर आप AutoResetEvent का उपयोग स्पष्ट

संबंधित मुद्दे