2009-05-16 15 views
0

私は非同期メソッド呼び出しをサポートするクラスを開発しようとしています。これは私が今までに思い付いたことですが、私はそれが正しいのかどうかは分かりません。非同期実装

私はasyncメソッドを一度実行したいだけで、複数の実行をサポートする必要はないので、AsyncOperationManagerクラスを使用しませんでした。

非同期パターンをよく知っている人は、フィードを返すことができますか?私はこれを正しい方法でやっていますか?

私は単一呼び出しの非同期メソッドに関する情報を見つけることができなかったので、助けてください。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.ComponentModel; 

namespace ConsoleApplication1 { 

    public delegate void WorkerDelegate(); 

    class Program { 

     static void Main(string[] args) { 

      String taskId = new Guid().ToString(); 

      AsyncTest test = new AsyncTest(); 
      test.DoSomethingLongAsyncCompleted += new AsyncCompletedEventHandler(test_DoSomethingLongAsyncCompleted); 
      test.DoSomethingLongProgressChanged += new ProgressChangedEventHandler(test_DoSomethingLongProgressChanged); 
      test.DoSomethingLongAsync(ItsOver, taskId); 

      // Cancel after 2 seconds 
      Thread.Sleep(2000); 
      test.DoSomethingLongCancelAsync(); 

      Console.ReadLine(); //Pause the console window 
     } 

     static void test_DoSomethingLongProgressChanged(object sender, ProgressChangedEventArgs e) { 
      Console.WriteLine("Percent complete: " + e.ProgressPercentage); 
     } 

     static void test_DoSomethingLongAsyncCompleted(object sender, AsyncCompletedEventArgs e) { 
      Console.WriteLine("Cancelled? " + e.Cancelled); 
      Console.WriteLine("Task ID: " + (String)e.UserState); 
     } 

     static void ItsOver(IAsyncResult r) { 
      Console.WriteLine("Task ID: " + (String)r.AsyncState); 
     } 
    } 

    class AsyncTest { 

     IAsyncResult _asyncResult = null; 
     Object _stateObj = null; 
     AsyncCallback _callBackDelegate; 

     public event ProgressChangedEventHandler DoSomethingLongProgressChanged; 
     public event AsyncCompletedEventHandler DoSomethingLongAsyncCompleted; 


     public IAsyncResult DoSomethingLongAsync(AsyncCallback userCallback, Object userState) { 

      if (_stateObj != null) 
       throw new InvalidOperationException("Method already started"); 

      WorkerDelegate worker = new WorkerDelegate(DoSomethingLong); 

      _callBackDelegate = userCallback; 
      _asyncResult = worker.BeginInvoke(null, userState); 

      return _asyncResult; 
     } 

     public void DoSomethingLongCancelAsync() { 
      _stateObj = null; 
     } 

     public void DoSomethingLong() { 

      // Set state object if method was called synchronously 
      if (_stateObj == null) 
       _stateObj = new Object(); 

      for (int i = 0; i < 10; i++) { 

       //If state object is null, break out of operation 
       if (_stateObj == null) break; 

       Thread.Sleep(1000); 
       Console.WriteLine("Elapsed 1sec"); 

       if (DoSomethingLongProgressChanged != null) { 
        // Percentage calculation for demo only :-) 
        DoSomethingLongProgressChanged(this, new ProgressChangedEventArgs(i+1 * 10, _stateObj)); 
       } 
      } 

      // Only execute if method was called async 
      if (_callBackDelegate != null) { 
       _callBackDelegate(_asyncResult); 

       DoSomethingLongAsyncCompleted(
        this, 
        new AsyncCompletedEventArgs(null, (_stateObj == null), _asyncResult.AsyncState) 
       ); 
      } 
     } 
    } 
} 

答えて

2

非同期モデルを処理する主な2つの方法があります。Asynchronous Programming ModelにあるこのMSDNの記事を参照してください。 IAsyncResultテクニックを使用しようとしているようです。私はこれを低レベルのシステムIO操作に使用する傾向があります。

UIやAPIでは、扱いやすいと思うので、イベントモデルに行く傾向があります。あなたのケースでは、QueueUserWorkItemにイベントを送信し、SynchronizationContextを追跡し、完了したイベントを発生させるときに使用することができます。 (WPFを使用している場合は、代わりにDispatchObjectを使用できます)。

これは私が以前使用したContactLoaderクラスです。

public class ContactLoader 
{ 
    public List<Contact> Contacts { get; private set; } 
    private readonly IRepository<Contact> contactsRepository; 

    public ContactLoader(IRepository<Contact> contactsRepository) 
    { 
     this.contactsRepository = contactsRepository; 
    } 

    public event AsyncCompletedEventHandler Completed; 
    public void OnCompleted(AsyncCompletedEventArgs args) 
    { 
     if (Completed != null) 
      Completed(this, args); 
    } 

    public bool Cancel { get; set; } 

    private SynchronizationContext _loadContext; 
    public void LoadAsync(AsyncCompletedEventHandler completed) 
    { 
     Completed += completed; 
     LoadAsync(); 
    } 
    public void LoadAsync() 
    { 
     if (_loadContext != null) 
      throw new InvalidOperationException("This component can only handle 1 async request at a time"); 

     _loadContext = SynchronizationContext.Current; 

     ThreadPool.QueueUserWorkItem(new WaitCallback(_Load)); 
    } 

    public void Load() 
    { 
     _Load(null); 
    } 

    private void _Load(object state) 
    { 
     Exception asyncException = null; 
     try 
     { 
      Contacts = contactsRepository.GetAll(); 

      if (Cancel) 
      { 
       _Cancel(); 
       return; 
      } 
     } 
     catch (Exception ex) 
     { 
      asyncException = ex; 
     } 

     if (_loadContext != null) 
     { 
      AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(asyncException, false, null); 
      _loadContext.Post(args => 
      { 
       OnCompleted(args as AsyncCompletedEventArgs); 
      }, e); 
      _loadContext = null; 
     } 
     else 
     { 
      if (asyncException != null) throw asyncException; 
     } 
    } 

    private void _Cancel() 
    { 
     if (_loadContext != null) 
     { 
      AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(null, true, null); 
      _loadContext.Post(args => 
      { 
       OnCompleted(args as AsyncCompletedEventArgs); 
      }, e); 
      _loadContext = null; 
     } 
    } 
} 
+0

ご返信ありがとうございます。 MSDNで見たすべての記事では、単一のInvokationsについては説明していませんが、私はこれをチェックします。再度、感謝します。 –

+0

サンプルEventModelでコード更新を追加しました。これが役立つかどうかを見てください。 – bendewey

+0

コードサンプルのヒープを感謝します。私が何を見つけることができるかを知るために読書を続けてください。 私は代わりにBackgroundWorkerクラスを使用すると考えるかもしれません。 –

関連する問題