C# 重置System.Timers.Timer以防止已发生事件

C# 重置System.Timers.Timer以防止已发生事件,c#,asp.net,static,timer,C#,Asp.net,Static,Timer,我正在尝试使用计时器触发事件,以便通过网络发送数据。我创建了一个简单的类进行调试。基本上我有一个列表我想发送。我希望发生以下情况: 将字符串添加到列表中 启动计时器10秒 将第二个字符串添加到计时器之前的列表中 在10秒后重新启动计时器 到目前为止,我有: public static List<string> list; public static Timer timer; public static bool isWiredUp = false; public static vo

我正在尝试使用
计时器
触发事件,以便通过网络发送数据。我创建了一个简单的类进行调试。基本上我有一个
列表
我想发送。我希望发生以下情况:

  • 将字符串添加到
    列表中
  • 启动
    计时器
    10秒
  • 将第二个字符串添加到
    计时器之前的
    列表中
  • 在10秒后重新启动计时器
  • 到目前为止,我有:

    public static List<string> list;
    public static Timer timer;
    public static bool isWiredUp = false;
    
    public static void Log(string value) {
        if (list == null) list = new List<string>();
        list.Add(value);
    
        //this does not reset the timer, elapsed still happens 10s after #1
        if (timer != null) {
            timer = null;
        }
    
        timer = new Timer(10000);
        timer.Start();
        timer.Enabled = true;
        timer.AutoReset = false;
    
        if (!isWiredUp) {
            timer.Elapsed += new ElapsedEventHandler(SendToServer);
            isWiredUp = true;
        }
    }
    
    static void SendToServer(object sender, ElapsedEventArgs e) {
        timer.Enabled = false;
        timer.Stop();
    }
    
    公共静态列表;
    公共静态定时器;
    公共静态bool isWiredUp=false;
    公共静态无效日志(字符串值){
    如果(list==null)list=newlist();
    列表。添加(值);
    //这不会重置计时器,经过的时间仍然发生在#1之后10秒
    如果(计时器!=null){
    定时器=空;
    }
    定时器=新定时器(10000);
    timer.Start();
    timer.Enabled=true;
    timer.AutoReset=false;
    如果(!isWiredUp){
    timer.appeased+=新的ElapsedEventHandler(SendToServer);
    isWiredUp=true;
    }
    }
    静态void SendToServer(对象发送方,ElapsedEventArgs e){
    timer.Enabled=false;
    timer.Stop();
    }
    

    有什么想法吗?

    你所实施的方法完全是错误的。看看消费者-生产者模型:

    您试图做的通常称为消费者/生产者数据流模型。从本质上说,您可以生成一个要发送到某处的数据列表,而不是每次向列表中添加一个项目时都发送它,您可以分组发送这些项目。。因此,您有一个生产者(发送数据的代码)和一个消费者(发送数据的代码)

    通常,这个问题可以通过生成一个线程来解决,该线程监视列表(通常是一个队列)并定期发送数据,最好的方法是使用EventWaitHandle

    下面是一些非常简化的代码作为示例

        class ServerStuff
    {
        public void Init()
        {
            datatosend = new List<string>();
                        exitrequest = new EventWaitHandle(false, EventResetMode.ManualReset); //This wait handle will signal the consumer thread to exit
            Thread t = new Thread(new ThreadStart(_RunThread));
            t.Start(); // Start the consumer thread...
        }
    
        public void Stop()
        {
            exitrequest.Set();
        }
    
        List<string> datatosend;
        EventWaitHandle exitrequest;
    
        public void AddItem(string item)
        {
            lock (((ICollection)datatosend).SyncRoot)
                datatosend.Add(item);
        }
    
        private void RunThread()
        {
            while (exitrequest.WaitOne(10 * 1000)) //wait 10 seconds between sending data, or wake up immediatly to exit request
            {
                string[] tosend;
                lock (((ICollection)datatosend).SyncRoot)
                {
                    tosend = datatosend.ToArray();
                    datatosend.Clear();
                }
    
                //Send the data to Sever here...
    
            }
        }
    }
    
    classserverstuff
    {
    公共void Init()
    {
    datatosend=新列表();
    exitrequest=new EventWaitHandle(false,EventResetMode.ManualReset);//此等待句柄将向使用者线程发出退出的信号
    线程t=新线程(新线程开始(_RunThread));
    t、 Start();//启动使用者线程。。。
    }
    公共停车场()
    {
    exitrequest.Set();
    }
    列出要发送的数据;
    EventWaitHandle exitrequest;
    公共无效附加项(字符串项)
    {
    锁定(((ICollection)datatosend.SyncRoot)
    datatosend.Add(项目);
    }
    私有void RunThread()
    {
    while(exitrequest.WaitOne(10*1000))//在发送数据之间等待10秒,或者立即唤醒以退出请求
    {
    字符串[]tosend;
    锁定(((ICollection)datatosend.SyncRoot)
    {
    tosend=datatosend.ToArray();
    datatosend.Clear();
    }
    //将数据发送到此处的服务器。。。
    }
    }
    }
    
    您可以使用
    停止
    功能,然后立即使用
    启动
    功能“重新启动”计时器。使用它,您可以在第一次创建类时创建
    计时器
    ,连接当时发生的事件,然后在添加项时只调用这两个方法。它将启动或重新启动计时器。请注意,在尚未启动的计时器上调用
    Stop
    ,没有任何作用,不会引发异常或导致任何其他问题

    public class Foo
    {
        public static List<string> list;
        public static Timer timer;
        static Foo()
        {
            list = new List<string>();
            timer = new Timer(10000);
            timer.Enabled = true;
            timer.AutoReset = false;
            timer.Elapsed += SendToServer;
        }
    
        public static void Log(string value)
        {
            list.Add(value);
            timer.Stop();
            timer.Start();
        }
    
        static void SendToServer(object sender, ElapsedEventArgs e)
        {
            //TODO send data to server
    
            //AutoReset is false, so neither of these are needed
            //timer.Enabled = false;
            //timer.Stop();
        }
    }
    
    公共类Foo
    {
    公共静态列表;
    公共静态定时器;
    静态Foo()
    {
    列表=新列表();
    定时器=新定时器(10000);
    timer.Enabled=true;
    timer.AutoReset=false;
    timer.appeased+=SendToServer;
    }
    公共静态无效日志(字符串值)
    {
    列表。添加(值);
    timer.Stop();
    timer.Start();
    }
    静态void SendToServer(对象发送方,ElapsedEventArgs e)
    {
    //TODO向服务器发送数据
    //AutoReset为false,因此不需要这两个选项
    //timer.Enabled=false;
    //timer.Stop();
    }
    }
    

    请注意,与使用
    列表相比,您很可能希望使用
    阻止集合
    。这有几个优点。首先,如果同时从多个线程调用
    Log
    方法,则该方法将起作用;按原样,多个并发日志可能会破坏列表。这还意味着
    SendToServer
    可以在添加新项目的同时将项目移出队列。如果使用
    列表
    ,则需要
    锁定对列表的所有访问权限(这可能不是问题,但不是那么简单)。

    使用IObservable(Rx)很容易实现这类功能

    让我们通过声明一个
    主题
    作为您的列表来简化问题,并继续使用.OnNext。一旦你有了一个可观察的对象,你就可以用System.Reactive.Linq的一条“线”做你想做的事情。这在下面的伪c中进行了说明#

    主题
    .Buffer(,1)//缓冲区,直到添加值或超时过期
    .订阅(x=>
    { 
    如果(x.Count==0)//超时已过期,请继续发送
    {
    SendAccumeratedListToServer();
    }   
    其他的
    {
    .添加(x);
    }
    });
    
    您的链接显示“此主题已过时”。并且没有包含有用的信息。我不知道您在谈论什么,也不知道该页面应该告诉我什么。这看起来更容易理解。我现在接受了另一个答案,我有一个会议,但会在会议结束后再看你的回答。如果您没有重置它,并且具有
    AutoReset=true
    ,同样的事情也会发生。当它没有设置为自动重置,并且在添加项目时重置时,情况就完全不同了。2.然后添加它,使您的代码按照问题的要求执行。3.不,不是。如果你想要证据,
     subject
    .Buffer(<your timespan>,1)   //buffer until either a value is added or the timeout expires
    .Subscribe(x => 
       { 
          if (x.Count == 0)  //the timeout expired so send on
          {
             SendAccumulatedListToServer(<your list>);   
             <clear your list>
          }   
          else
          {
             <your list>.Add(x);
          }
       });