2

this 토론을 기반으로 타이머 클래스를 만들었지 만 문제가 있습니다. 경과 된 이벤트는 한 번만 발생합니다. 작은 문제 : Start()를 호출 할 때마다 _timer를 인스턴스화 할 필요가 없다면 좋은 일입니다. 당신이 작업에 타이머를 구현에 관심이 코드를 시도 할 경우휴대용 클래스 라이브러리의 타이머

using System; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Diagnostics.Contracts; 

namespace JellystonePark.Model 
{ 
    internal delegate void TimerCallback(object state); 
    internal sealed class Timer : CancellationTokenSource, IDisposable 
    { 
     internal Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period) 
     { 
      Contract.Assert(period == TimeSpan.FromMilliseconds(-1), "This stub implementation only supports dueTime."); 
      Task.Delay(dueTime, Token).ContinueWith((t, s) => 
      { 
       var tuple = (Tuple<TimerCallback, object>)s; 
       tuple.Item1(tuple.Item2); 
      }, Tuple.Create(callback, state), CancellationToken.None, 
       TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, 
       TaskScheduler.Default); 
     } 

     public new void Dispose() { base.Cancel(); } 
    } 
    public class PCLTimer 
    { 
     private Timer _timer; 
     private TimeSpan _interval; 

     /// <summary> 
     /// Interval between signals in milliseconds. 
     /// </summary> 
     public double Interval 
     { 
      get { return _interval.TotalMilliseconds; } 
      set { _interval = TimeSpan.FromMilliseconds(value); Stop(); Start(); } 
     } 

     /// <summary> 
     /// True if PCLTimer is running, false if not. 
     /// </summary> 
     public bool Enabled 
     { 
      get { return null != _timer; } 
      set { if (value) Start(); else Stop(); } 
     } 

     /// <summary> 
     /// Occurs when the specified time has elapsed and the PCLTimer is enabled. 
     /// </summary> 
     public event EventHandler Elapsed; 

     /// <summary> 
     /// Starts the PCLTimer. 
     /// </summary> 
     public void Start() 
     { 
      if (0 == _interval.TotalMilliseconds) 
       throw new InvalidOperationException("Set Elapsed property before calling PCLTimer.Start()."); 
      _timer = new Timer(OnElapsed, null, _interval, _interval); 
     } 

     /// <summary> 
     /// Stops the PCLTimer. 
     /// </summary> 
     public void Stop() 
     { 
      _timer.Dispose(); 
     } 

     /// <summary> 
     /// Releases all resources. 
     /// </summary> 
     public void Dispose() 
     { 
      _timer.Dispose(); 
     } 

     /// <summary> 
     /// Invokes Elapsed event. 
     /// </summary> 
     /// <param name="state"></param> 
     private void OnElapsed(object state) 
     { 
      if (null != _timer && null != Elapsed) 
       Elapsed(this, EventArgs.Empty); 
     } 
    } 
} 
+0

답변을 찾고있는 실제 질문이 명확하지 않습니다. –

+0

타이머가 두 번 이상 작동하려면 * 마침표 *를 지정해야합니다. 그러면 왜이 코드가 짜증나는지 알게 될 것입니다. –

+0

@HansPassant 기간을 정의하는 방법에 대해 알고 싶습니까? 전체 작업 코드, 일부 guidlines, 시작하는 방법을 원하지 않습니다. 나는 pcl 라이브러리에 타이머를 구현해야하는데, 어떤 해결책도 찾지 못했다. –

답변

2

는 :

public delegate void TimerCallback(object state); 

public sealed class Timer : CancellationTokenSource, IDisposable 
{ 
    public Timer(TimerCallback callback, object state, int dueTime, int period) 
    { 
     Task.Delay(dueTime, Token).ContinueWith(async (t, s) => 
     { 
      var tuple = (Tuple<TimerCallback, object>) s; 

      while (true) 
      { 
       if (IsCancellationRequested) 
        break; 
       Task.Run(() => tuple.Item1(tuple.Item2)); 
       await Task.Delay(period); 
      } 

     }, Tuple.Create(callback, state), CancellationToken.None, 
      TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion, 
      TaskScheduler.Default); 
    } 

    public new void Dispose() { base.Cancel(); } 
} 

은 이미 당신이 어떤 인터페이스에 의존성을 소개하고 당신에게 특정 타이머 구현을 제공하기 위해 사용자를 요청할 수 있습니다 언급했다.

+1

'while (! IsCancellationRequested)'로 변경하는 것이 가치가 있습니다. –

관련 문제