2011-11-19 20 views
6

実行時例外が発生し、以下の例を実行しようとしています。TaskScheduler.FromCurrentSynchronizationContext()in .NET

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 

コードサンプル:

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); 
     } 
    } 
} 

任意のアイデア?

答えて

7

m_syncContextTaskSchedulerの作成をフォームコンストラクタに置きます。

public MyForm() { 
    Text = "Synchronization Context Task Scheduler Demo"; 
    Visible = true; Width = 400; Height = 100; 
    m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
} 
+0

ありがとうございます!それは働く、それの後ろの理由は何ですか? – Pingpong

+3

変数の初期化中に 'FromCurrentSynchronizationContext()'が有効なコンテキストにないため(UIスレッド内にある必要があります)。ああ、答えを受け入れてください、それは人々があなたを助けることを奨励します:) – Alex

6

ありがとう!それは働く、それの後ろの理由は何ですか?

コンストラクタは早すぎる初期化子を持って読み取り専用メンバーを初期化しているため。 Formクラスのコンストラクタは、必要に応じてWindowsFormsSynchronizationContextという名前のクラスのインスタンスである同期プロバイダをインストールします。 C#コンパイラは、の前に読み取り専用初期化子のコードを生成して、基本クラスのコンストラクタを呼び出します。代入をコンストラクター本体に移すと、の後に基本コンストラクターが呼び出され、が初期化されます。

readonlyメンバーイニシャライザには注意してください。

+0

説明をありがとう。 – Pingpong