在 运行 2 个或更多任务并行时保留变量值

Retain variable values while running 2 or more tasks in parallel

我正在使用计时器,并将线程化作为解决问题的第一步。我必须每 30 秒发送一些参考,每次单击按钮时都会创建此参考。所以我有以下代码:

public MyReference SomeReference {get;set;}
public string MyFullName {get;set;} //this is bound to WPF textbox

public bool Saved()
{
     SomeReference.Id = GeneratedId;
     SomeReference.FullName = MyFullName;

     return SavedtoDB(SomeReference);
}

public void OnButtonClick()
{
    if(Saved()) //timer should only start if it is already saved in the database
         var t = new Thread(() => ExecuteTimer(SomeReference));
}

public void ExecuteTimer(MyReference someReference)
{
    System.Timers.Timer sendTimer = new System.Timers.Timer(30000);
    sendTimer.Elapsed += (sender, e) => ExecuteElapsed(sender, e, someReference, sendTimer);
    sendTimer.Start();
}

public void ExecuteElapsed(object source, ElapsedEventArgs e, MyReference someReference, System.Timers.Timer sendtimer)
{
    sendtimer.Stop();
    Send(someReference);
}

以下是MyReference class:

public class MyReference()
{
    public string Id {get;set;}
    public string FullName {get;set;}
}

编辑问题重点:

问题是它只发送最新的值 someReference 而忽略之前的值。如何在 30 秒后发送每个值而不用 someReference 的最新值替换它们?

以下是启动任务的方法,每次单击按钮时都会延迟 30 秒发送参考。

public void OnButtonClick()
{
    var localCopyOfTheReference = someReference;
    var fireAndForget = Task.Run(async () =>
    {
        await Task.Delay(30000);
        Send(localCopyOfTheReference);
    });
}

如果出现异常,异常会被吞掉

维护所有这些计时器似乎真的很混乱。

为什么不只维护一个您希望事件发生的时间列表?并使事件成为委托。

ConcurrentDictionary<DateTime,Action> events = new ConcurrentDictionary<DateTime,Action>();

当有人点击某物时,

events.TryAdd(DateTime.Now.AddSeconds(30), () => HandleEvent(whatever, you, want));

在处理程序中,确保没有后续事件。

void HandleEvent()
{
    if (events.Keys.Any( dateKey => dateKey > DateTime.Now )) return;

    DoStuff();
}

现在您只需要一种让事件发生的方法。

timer.Elapsed += (s,e) => {
    var list = events.Where( item => item.Key <= DateTime.Now ).ToList();
    foreach (var item in list)
    {
        item.Value.Invoke();
        events.TryRemove(item);
    }
};

您似乎需要 deep clone 对象。

让我解释一下为什么对您的对象的引用是不够的。 SomeReference 变量将始终指向您的 MyReference 实例所在的内存位置。如果你点击你的按钮,这个数据是 written/overwritten。当你的定时器触发时,它总是会加载位于 SomeReference 的任何数据并发送它。

实施深层复制会将您的实例物理复制到内存中,因此您将保留对象的副本,该副本可用于发送而不会被您的 Save() 调用覆盖。

要实现这一点,您可以(还有很多其他方法)使用 ICloneable 接口,如下所示:

  class MyReference : ICloneable
  {
    public string Id { get; set; }
    public string FullName { get; set; }

    public object Clone()
    {
      return new MyReference()
      {
        Id = this.Id,
        FullName = this.FullName
      };
    }
  }

现在单击按钮时,您可以使用 Theodors Task.Delay 方法并为其提供对象的副本:

    public void OnButtonClick()
    {
      //Here we now copy the complete object not just the reference to it
      var localCopyOfTheReference = (MyReference)someReference.Clone();

      var fireAndForget = Task.Run(async () =>
      {
        await Task.Delay(30000);
        Send(localCopyOfTheReference);
      });
    }