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