【问题标题】:How do I pass an object into a timer event?如何将对象传递给计时器事件?
【发布时间】:2020-06-11 00:05:17
【问题描述】:

好的,我在 .Net 4 中使用 System.Timers.Timer 和 C#。

我的计时器对象是这样的:

var timer = new Timer {Interval = 123};

我的 Timer Elapsed 事件处理程序指向一个方法,如下所示:

timer.Elapsed += MyElapsedMethod;

我的方法是这样的:

static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
    Console.WriteLine("Foo Bar");
}

我想将一个字符串传递给这个方法,我该怎么做?

谢谢

【问题讨论】:

    标签: c# timer


    【解决方案1】:

    最简单的方法是将事件处理程序更改为匿名函数。它允许您在声明点传递字符串。

    string theString = ...;
    timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);
    
    static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
      ...
    }
    

    【讨论】:

    • 其实你还在读一些全局变量(是的,它可能是本地的,但它没有意义)。刚刚用匿名函数替换了事件处理程序。这个timer.Elapsed += (s,e) => Console.WriteLine(theString); 更短,但想法相同。
    • 我认为不鼓励内联分配事件处理程序,因为它们之后无法释放?
    【解决方案2】:

    如果您希望能够再次取消注册“Elapsed”事件处理程序,则不应使用委托而不将其记住在变量中。

    所以另一种解决方案可能是创建一个基于 Timer 的自定义类。只需添加您喜欢的任何成员,然后从“Elapsed”事件处理程序的“sender”参数中获取您的自定义 Timer 对象:

    class CustomTimer : System.Timers.Timer
    {
        public string Data;
    }
    
    private void StartTimer()
    {
        var timer = new CustomTimer
        {
            Interval = 3000,
            Data = "Foo Bar"
        };
    
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }
    
    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        string data = ((CustomTimer)sender).Data;
    }
    

    这种策略当然也适用于其他事件和类,只要基类不是密封的。

    【讨论】:

    • 这似乎比选择的答案更好,因为您有机会取消订阅 Elapsed 事件。这也是装饰者模式。
    【解决方案3】:

    您可以将字符串保存在某个对象中并在事件处理程序中读取它:

    static string _value;
    
    static void MyElapsedMethod(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine(_value);
    }
    

    更新:相同的代码通过不同的语法: timer.Elapsed += (s,e) => Console.WriteLine(_value);

    更新:考虑同时使用 System.Threading.Timer

    State state = new State();
    Timer timer = new Timer(OnTimer, state, 0, 123);
    state.Value = "FooBar"; // change state object
    

    您可以在计时器回调中检索状态:

    static void OnTimer(object obj)
    {
        State state = obj as State;
        if (state == null)
            return;        
    
        Console.WriteLine(state.Value);
    }
    

    【讨论】:

    • 嗯这就是我正在做的,我正在寻找更直接的路线!
    【解决方案4】:
     Timer aTimer = new Timer(300);
                    aTimer.Elapsed += delegate { PublishGPSData(channel, locationViewModel); };
                    // Hook up the Elapsed event for the timer. 
                    aTimer.AutoReset = true;
                    aTimer.Enabled = true;
    private void PublishGPSData(IModel channel, LocationViewModel locationViewModel)
    {
    };
    

    【讨论】:

      【解决方案5】:

      使用同一个类中的一个字段来保存你想要的任何字符串,然后在你经过的事件处理程序中检索它。但是,您必须小心跨线程问题。

      【讨论】:

        【解决方案6】:

        我写了这个简单的类来处理这个问题:

        using System;
        using System.Timers;
        
        namespace MyProject.Helpers
        {
            public class MyTimer
            {
                private volatile Timer _timer = new Timer();
                private volatile bool _requestStop = false;
                private MyElapsedEventHandler _eventHander;
                private MyElapsedEventHandlerWithParam _eventHandlerWithParam;
                private object _param;
        
                public MyTimer(int interval, MyElapsedEventHandler elapsedEventHandler, bool autoReset = false)
                {
                    _timer.Interval = interval;
                    _timer.Elapsed += ElapsedWrapper;
                    _timer.AutoReset = autoReset;
        
                    _eventHander = elapsedEventHandler;
        
                    Start();
                }
        
                public MyTimer(int interval, MyElapsedEventHandlerWithParam elapsedEventHandler, object param, bool autoReset = false)
                {
                    _timer.Interval = interval;
                    _timer.Elapsed += ElapsedWrapperWithParam;
                    _timer.AutoReset = autoReset;
        
                    _eventHandlerWithParam = elapsedEventHandler;
                    _param = param;
        
                    Start();
                }
        
                private void ElapsedWrapper(object sender, ElapsedEventArgs e)
                {
                    if (!_requestStop && _eventHander != null)
                    {
                        _eventHander();
                    }
                }
        
                private void ElapsedWrapperWithParam(object sender, ElapsedEventArgs e)
                {
                    if (!_requestStop && _eventHandlerWithParam != null)
                    {
                        _eventHandlerWithParam(_param);
                    }
                }
        
                public void Stop()
                {
                    _requestStop = true;
                    _timer.Stop();
                }
        
                public void Start()
                {
                    _requestStop = false;
                    _timer.Start();
                }
            }
        
            public delegate void MyElapsedEventHandlerWithParam(object param);
            public delegate void MyElapsedEventHandler();
        }
        

        像这样使用它:

        void Main(string[] args){
            new MyTimer(durationInSeconds * 1000, EventHandler, "some string");
        }
        
        void EventHandler(object param){
            doSomethingWithString((string)param);
        }
        

        如果您编辑委托(以及在MyTimer 类中调用事件处理程序),您还可以传递事件参数或任何类型的参数。

        【讨论】:

          【解决方案7】:

          为什么不直接使用 Timer 和 ElapsedEventHandler?

          namespace TimerEventHandler
          {
              class Program
              {
                  private static Timer myEventTimer;
          
                  static void Main(string[] args)
                  {
                      // 5 second timer multiply 1000 milliseconds by the time
                      //e.g. new Timer(60 * 1000 * 10) = 10 minutes
                      myEventTimer = new Timer(5 * 1000 * 1);
                      myEventTimer.Enabled = true;
                      myEventTimer.Elapsed += new ElapsedEventHandler(TimerSchedule_Elapsed);
          
                      Console.WriteLine("Timer started!");
          
                      // make a thread and wait forever just so console does not go away
                      Thread.Sleep(Timeout.Infinite);
                  }
          
                  private static void TimerSchedule_Elapsed(object sender, ElapsedEventArgs e)
                  {
                      // do something
                      Console.WriteLine("Timer elapsed!");
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-10-10
            • 1970-01-01
            • 2010-11-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多