[英]TaskScheduler.FromCurrentSynchronizationContext() in .NET
I am getting a runtime exception trying to run the example below. 我试图运行下面的示例时遇到运行时异常。
Unhandled Exception: System.InvalidOperationException: The current SynchronizationContext may not be used as a TaskScheduler.
at System.Threading.Tasks.SynchronizationContextTaskScheduler..ctor()
at System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext()
at TaskDemo.MyForm..ctor() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\MyApp\Hello.cs:line 428
at TaskDemo.SynchronizationContextTaskScheduler() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\MyApp\Hello.cs:line 396
at TaskDemo.Go() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\CLRviaCSharp\Hello.cs:line 214
at ComputeOps.Main() in D:\myStudio\ASPNet\CSharp\CSharp4\MyApp\CLRviaCSharp\Hello.cs:line 23
Code sample: 代码示例:
public class TaskSchedulerTest {
public void Test() {
SynchronizationContextTaskScheduler();
}
private void SynchronizationContextTaskScheduler() {
var f = new MyForm();
System.Windows.Forms.Application.Run();
}
private sealed class MyForm : System.Windows.Forms.Form {
public MyForm() {
Text = "Synchronization Context Task Scheduler Demo";
Visible = true; Width = 400; Height = 100;
}
private readonly TaskScheduler m_syncContextTaskScheduler =
TaskScheduler.FromCurrentSynchronizationContext();
private CancellationTokenSource m_cts;
protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
if (m_cts != null) { // An operation is in flight, cancel it
m_cts.Cancel();
m_cts = null;
} else { // An operation is not in flight, start it
Text = "Operation running";
m_cts = new CancellationTokenSource();
// This task uses the default task scheduler and executes on a thread pool thread
var t = new Task<Int32>(() => Sum(m_cts.Token, 20000), m_cts.Token);
t.Start();
// These tasks use the synchronization context task scheduler and execute on the GUI thread
t.ContinueWith(task => Text = "Result: " + task.Result,
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
m_syncContextTaskScheduler);
t.ContinueWith(task => Text = "Operation canceled",
CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
m_syncContextTaskScheduler);
t.ContinueWith(task => Text = "Operation faulted",
CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
m_syncContextTaskScheduler);
}
base.OnMouseClick(e);
}
}
}
Any idea? 任何的想法?
put the creation of m_syncContextTaskScheduler
into your form constructor . 将m_syncContextTaskScheduler
的创建放入表单构造函数中。
public MyForm() {
Text = "Synchronization Context Task Scheduler Demo";
Visible = true; Width = 400; Height = 100;
m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
Thanks! 谢谢! It works, what is the reason behind it? 它有效,它背后的原因是什么?
Because the constructor initializes the readonly members that have an initializer too soon. 因为构造函数很快初始化具有初始化程序的只读成员。 The Form class constructor installs the synchronization provider if needed, an instance of a class named WindowsFormsSynchronizationContext. 如果需要,Form类构造函数安装同步提供程序,即名为WindowsFormsSynchronizationContext的类的实例。 The C# compiler generates the code for readonly initializers before calling the base class constructor. 在调用基类构造函数之前 ,C#编译器为readonly初始化程序生成代码。 Moving the assignment into the constructor body ensures that it is initialized after calling the base constructor. 将赋值移动到构造函数体中可确保在调用基础构造函数后初始化它。
Be careful with readonly member initializers, keep them simple. 注意只读成员初始化程序,保持简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.