2014-12-13 24 views
5

के साथ एक निश्चित समय पर फ़ंक्शन को कॉल करें क्या प्रतिक्रियाशील एक्सटेंशन का उपयोग करके किसी निश्चित समय पर फ़ंक्शन को कॉल करना संभव है?सी # प्रतिक्रियाशील एक्सटेंशन

उदाहरण के लिए, अगर मैं वास्तव में 9 और 1 में विधि foo() कॉल करने के लिए, हर रोज चाहता हूँ, मुझे Timer वर्ग अगर यह 9:00 या 1:00, या यहाँ तक Observable.Interval समारोह है हर कुछ सेकंड की जाँच करने के इस्तेमाल कर सकते हैं। लेकिन क्या ऐसा करने का एक और अधिक प्रभावी तरीका है? तो मैं foo() को अभी तक कॉल करने का समय होने पर हर कुछ सेकंड की जांच नहीं कर रहा हूं, बल्कि एक अवलोकन करने योग्य है जो सही समय पर foo() को कॉल करेगा।

+0

आप अगले ट्रिगर तक समय की गणना कर सकते हैं और उस टाइमआउट के साथ टाइमर का उपयोग कर सकते हैं (पैरामीटर 'देयटाइम' को [थ्रेडिंग टिमर] में देखें (http://msdn.microsoft.com/en- हमें/लाइब्रेरी/3yb9at7c (v = vs.110) .aspx)) – Jcl

+4

अपना कोड इस तरह से लिखें कि आप विंडोज टास्क शेड्यूलर का उपयोग कर सकते हैं क्योंकि यह डिज़ाइन है डी के लिए – JRLambert

उत्तर

5

बस Timer के अधिभार का उपयोग करें जो DateTimeOffset मान स्वीकार करता है। आप "पूर्ण अंतराल" बनाने के लिए Defer और Repeat का उपयोग कर सकते हैं।

Observable.Defer(() => 
    DateTime.Now.Hour < 9 
    ? Observable.Timer(DateTime.Today.AddHours(9)) 
    : DateTime.Now.Hour < 13 
    ? Observable.Timer(DateTime.Today.AddHours(13)) 
    : Observable.Timer(DateTime.Today.AddDays(1).AddHours(9))) 
      .Repeat() 
      .Subscribe(...); 

आरएक्स automatically ensures, अपनी क्षमता के अनुसार, कि अपनी अधिसूचना भी टाइमर बहाव के संबंध में और अगर टाइमर अवधि से पहले सिस्टम घड़ी परिवर्तन नहीं बीत जाती, निर्दिष्ट सटीक तिथि और समय पर हो जाएगा।

यहां एक विस्तार विधि है जो समस्या को और सामान्यीकृत करती है।

उपयोग:

Observable2.Daily(TimeSpan.FromHours(9), TimeSpan.FromHours(13)).Subscribe(...); 

परिभाषा:

public static partial class Observable2 
{ 
    public static IObservable<long> Daily(params TimeSpan[] times) 
    { 
    Contract.Requires(times != null); 
    Contract.Requires(Contract.ForAll(times, time => time > TimeSpan.Zero)); 
    Contract.Requires(Contract.ForAll(times, time => time.TotalDays < 1)); 

    return Daily(Scheduler.Default, times); 
    } 

    public static IObservable<long> Daily(IScheduler scheduler, params TimeSpan[] times) 
    { 
    Contract.Requires(times != null); 
    Contract.Requires(Contract.ForAll(times, time => time > TimeSpan.Zero)); 
    Contract.Requires(Contract.ForAll(times, time => time.TotalDays < 1)); 

    if (times.Length == 0) 
     return Observable.Never<long>(); 

    // Do not sort in place. 
    var sortedTimes = times.ToList(); 

    sortedTimes.Sort(); 

    return Observable.Defer(() => 
     { 
     var now = DateTime.Now; 

     var next = sortedTimes.FirstOrDefault(time => now.TimeOfDay < time); 

     var date = next > TimeSpan.Zero 
       ? now.Date.Add(next) 
       : now.Date.AddDays(1).Add(sortedTimes[0]); 

     Debug.WriteLine("Next @" + date + " from " + sortedTimes.Aggregate("", (s, t) => s + t + ", ")); 

     return Observable.Timer(date, scheduler); 
     }) 
     .Repeat() 
     .Scan(-1L, (n, _) => n + 1); 
    } 
} 

अद्यतन:

आप इनपुट को परिभाषित करते हुए अधिक "कार्यात्मक" अपने दृष्टिकोण में होना चाहते हैं एक पुनरावर्तक से एक अनंत अनुक्रम के रूप में ब्लॉक, प्रति जेरोन मोस्टर्ट के उत्तर, तो आप निम्नानुसार Generate का उपयोग कर सकते हैं।

Observable.Generate(
    GetScheduleTimes().GetEnumerator(), 
    e => e.MoveNext(), 
    e => e, 
    e => e.Current, 
    e => e.Current); 

जेरोन Mostert के जवाब (नष्ट कर दिया) GetScheduleTimes का एक उदाहरण दिया गया प्रदान की है, लेकिन मूल रूप से यह सिर्फ एक iterator ब्लॉक कि थोड़ी देर के पाश में DateTimeOffset मूल्यों की एक अनंत अनुक्रम झुकेंगे, प्रत्येक पाश मूल्यों 'बढ़ाने के साथ था दिन 1.

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