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

我正在使用计时器,并且已将线程化作为解决问题的第一步。我必须每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类:

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

编辑以强调问题:

问题在于它仅发送最新值someReference,而忽略先前的值。我将如何在30秒后发送每个值,而又不将它们替换为最新的someReference值?

moon5422 回答:并行运行2个或更多任务时保留变量值

似乎您需要deep clone个对象。

让我解释一下为什么对您的对象的引用不够。 SomeReference变量将始终仅指向您的MyReference实例所在的内存位置。如果单击按钮,则该数据将被写入/覆盖。当您的计时器触发时,它将始终加载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);
      });
    }
,

在这里,您可以启动每单击一次按钮将延迟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);
    }
};
本文链接:https://www.f2er.com/3153902.html

大家都在问