C# 通过定时器c控制函数调用#

C# 通过定时器c控制函数调用#,c#,function,timer,onclick,C#,Function,Timer,Onclick,尽管最终用户发出请求,但仅在特定时间间隔后调用函数 public override void SendNotificationMessage(NotificationMessageRequest request) {......} 这是我的功能,当有点击动作时会触发 我希望只在特定的时间间隔(比如5分钟)调用它。尽管用户在该时间间隔之前发出请求 我试图用一个计时器来达到我的目的,但问题是每次用户点击时,计时器都会重新启动。那么,一个函数怎么能由计时器控制呢 PS:我不能在用户应用程序中

尽管最终用户发出请求,但仅在特定时间间隔后调用函数

public override void SendNotificationMessage(NotificationMessageRequest request)
    {......}
这是我的功能,当有点击动作时会触发

我希望只在特定的时间间隔(比如5分钟)调用它。尽管用户在该时间间隔之前发出请求

我试图用一个计时器来达到我的目的,但问题是每次用户点击时,计时器都会重新启动。那么,一个函数怎么能由计时器控制呢


PS:我不能在用户应用程序中进行更改,在用户应用程序中进行单击是一种快速解决方案,我可以建议保留一个代理列表,其中包含您希望在每个计时器计时时调用的方法。因此,在用户操作中,您只需添加要调用的方法。如果每个用户调用的参数必须是唯一的,则可以在以下代码中执行类似操作:

// This is the class handling the timer ticks
public class ActionExecutor : IDisposable
{
    private Timer timer;

    private IList<Action> actionsList = new List<Action>();

    public ActionExecutor()
    {
        // choose the interval as suits you best, or use 
        // constructor argument
        timer = new Timer(1000);
        timer.Elapsed += OnTimerTick;
        timer.AutoReset = true;
        timer.Start();
    }

    void OnTimerTick(object sender, ElapsedEventArgs)
    {
        lock(actionsList)
        {
            foreach(Action a in actionsList) 
            {
                a();
            }
            actionsList.Clear();
        }
    }

    public void AddAction(Action a)
    {
        lock(actionList)
        {
            actionList.Add(a);
        }
    }

    public void Dispose()
    {
        // we must stop the timer when we are over
        if (timer != null)
        {
            timer.Stop();
        }
        if (actionList != null)
        {
            actionList.Clear();
        }
    }
    ~ActionExecutor()
    {
        Dispose();
    }
}
在上面的代码中,必须确保您使用的是处理用户操作的相同的
ActionExecutor
实例。请注意与锁的同步-计时器通常在单独的线程中运行,而不是在添加操作的线程中运行。如果您说的是web应用程序,那么每个用户都在自己的线程中运行,因此多个用户同时也会增加并发性。此外,您可能需要添加适当的错误处理,因为为了简洁起见,我省略了该部分


更新


正如注释中所建议的,使用不同于列表的集合来保存操作可能会使您受益。这取决于您场景的实际需要。

我在当前系统中也做了类似的事情。在我的例子中,我对数据请求进行批处理,这样就可以将它们组合成一个,而不是对远程服务进行多次调用

这是系统的高级概述:

我有一个CollatorClass,它有一个方法MakeRequest() 在内部,CollatorClass有一个初始化为null的计时器对象和一个包含请求详细信息的对象列表

调用MakeRequest时: 如果计时器为空,则启动计时器。 请求的详细信息将添加到列表中

当计时器计时结束时,系统从列表中读取所有请求的详细信息,并采取适当的操作。 (请注意,您可能需要使用lock以确保所有线程安全)

如果需要,还可以传递一个操作引用,以便在实际执行数据请求时调用。不过,我不确定这在您的情况下是否有必要


如果你想了解更多细节,请告诉我。

首先,你应该在课堂上添加一个词汇:

Dictionnary<int, NotificationMessageRequest> _notifications
然后在计时器事件上调用此方法:

private void SendNotifications()
{
    lock(_notifications)
    {
        foreach(KeyValuePair<int, NotificationMessageRequest> p in _notifications)
            SendNotificationMessage(p.Value);

        _notifications.Clear();
    }
}
private void SendNotifications()
{
锁定(_通知)
{
foreach(KeyValuePair p in_通知)
SendNotificationMessage(p.值);
_通知。清除();
}
}

如果你做了类似的事情,你就会有你需要的行为。

创建一个计时器,并将其间隔设置为一个合适的值。然后声明一个类型为
System.Collections.Concurrent.ConcurrentQueue
(如果合适,则为静态)的字段,并将消息放入
OnClick
中的队列中


当计时器滴答声调用
TryDequeue
并处理消息时。

您是否可以发布更多的SO示例代码以进行解密?您的应用程序中是否有多个用户可以调用此函数?是的,将有多个用户,并且一旦调用此函数,将向其他人发送一些通知……因此,为了防止垃圾邮件,我很抱歉寻找此函数的及时调用我不认为
操作的
列表
就足够了,它应该是一个
字典
或基于用户ID的其他东西。否则,用户可以计划多次执行相同的操作,而不必注意it@ppetrov是的,如果OP希望避免重复或以其他方式管理添加的项目,这可能是一种更好的方法。我选择了
List
以允许按添加的顺序执行操作。这并不能解决我的问题,因为每次单击按钮时,只会调用同一个函数,对于该函数,我需要一些计时器,并且您的代码只能在有多个计时器时使用functions@Raghu,我跳过了那部分,因为我想强调动作的存储和处理。我已经对代码进行了编辑,添加了一个更完整的带有计时器的
ActionExecutor
。@IvayloSlavov当然我很抱歉!没想到,我被我的循环场景卡住了哈哈!我将删除相关注释,因为它们对问题没有用处我不会批处理请求…我将阻止请求,因此只会执行及时调用,其他调用将不会执行。您可以通过更改MakeRequest方法来实现这一点,如果计时器为空,则仅将请求添加到列表中。(哦,别忘了在timer tick方法的末尾将timer对象设为null。)让我为一个用户执行此操作…我有一个用户,他可能会发出多个请求..首先让我解决这个问题,将来可能会有多个用户…单用户调用onClick()因此,该函数执行一次,即使他再次调用onClick(),也不应该调用该函数。这将适用于您想要的所有用户。但是通过这种方式,您的函数只会每五分钟执行一次(例如)。如果用户单击按钮,计时器还没有勾选,它将在稍后执行该功能+1收集
NotificationMessageRequest
对于OP来说是一种更简单、可能更好的方法。是的,我尝试过,但每次都是onClick()因此,我阻止函数的目的将无法实现。为什么要重新启动计时器?如果这是一个web应用程序,则将其设置为静态字段(显然,您的勾号处理程序也将是静态的)。您是否每次调用OnClick时都创建计时器?不,我正在为每个OnClick创建计时器,但我
private void PlanNotification(NotificationMessageRequest request, int userId)
{
    // or grab the userId from where you can
    lock(_notifications) // if needed ?
    {
        if (_notifications.Contains(userId)) return;

        _notifications.Add(userId, request);
    }
}
private void SendNotifications()
{
    lock(_notifications)
    {
        foreach(KeyValuePair<int, NotificationMessageRequest> p in _notifications)
            SendNotificationMessage(p.Value);

        _notifications.Clear();
    }
}