2016-04-19 19 views
0

私は外部クラスから標準の.Netイベントを受け取るクラスを持っています。 これらのイベントには、イベントを同期させるために使用できるアドレスプロパティがあります(他の多くのプロパティに加えてもちろん)。何かを取得して正しいイベントを待つメソッドを作成できるはずですGetメソッドのイベントからデータを返します。非同期イベントの同期

しかし、私はC#の同期にかなり新しく、あなたのうちの誰かが私を助けてくれることを願っていました。

  1. 誰かがメソッドがイベントを待つが、同じアドレス(または、それまでのタイムアウトする)
  2. イベントをチェックして受信されたことをDoAsynchronousToSynchronousCall
  3. を呼び出します。以下は、私が達成したいもののため、多少の擬似コードであります現在のすべての要求に対してそれは同じアドレスで要求を見つけた場合、DoAsynchronousToSynchronousCallは返信が
  4. DoAsynchronousCall
  5. を到着した知らせを取得(または取得)返事をし、私は私のように感じる

public class MyMessage 
{ 
    public string Address { get; set; } 
    public string Data { get; set; } 
} 

public Main 
{ 
    externalClass.MessageReceived += MessageReceived; 
} 

public void MessageReceived(MyMessage message) 
{ 
    MyMessage request = _requestQueue.FirstOrDefault(m => m.Address = message.Address); 
    if (request != null) 
    { 
     // Do something to let DoAsynchronousToSynchronousCall() know the reply has arrived 
    } 
} 

private List<MyMessage> _requestQueue = new List<MyMessage>(); 
public MyMessage DoAsynchronousToSynchronousCall(MyMessage message) 
{ 
    _requestQueue.Add(message); 
    externalClass.Send(message); 

    // Do something to wait for a reply (as checked for above) 
    MyMessage reply = WaitForCorrectReply(timeout: 10000); 
    return reply; 
} 

、呼び出し元に返しますasyncawaitを使用する機会が紛失しています(まだ私にはわかりません)。上記の情報に基づいて私が達成しようとしていることを理解できることを願っています。

答えて

-1

スレッドブロッキングと非ブロッキングの動作を切り替えるソートの「トグル」として機能するManualResetEventがあります。 DoAsynchronousToSynchronousCallReset、次にWaitOne(int timeoutMilliseconds)はスレッドをブロックするイベントで、正しい応答が到着したことを確認するとSetコールが実行され、正しいものが到着した場合にスレッドが途中で続行されます。

+0

はい、しかし、複数の発信者は 'DoAsynchronousToSynchronous'を呼び出す場合どのように扱うのでしょうか? 1つの「ManualResetEvent」だけが1人の発信者に適しているのではないでしょうか? – GTHvidsten

+1

リセットイベントを 'MyMessage'に追加して、それぞれが独自のコピーを取得するようにしました –

+0

@ ScottChamberlainの説明のおかげで、私は' ManualResetEvent'で動作させることができました:) – GTHvidsten

0

実際には、複数のコールを同時に実行することはできず、同期応答もあります。複数の通話に対して同期応答を必要とする場合は、同期呼び出しも同時に行う必要があります。

Microsoftのリアクティブエクステンション(NuGet "Rx-Main")を使用して、できるだけシンプルにすることを検討します。 Rxを使用すると、イベントをクエリの値のストリームに変換できます。

ここで私は何をしますか。

私が最初にこのようなIObservable<MyMessage> receivedMessagesとして受信したメッセージの流れを定義します

receivedMessages = 
    Observable 
     .FromEvent<MessageReceivedHandler, MyMessage>(
      h => externalClass.MessageReceived += h, 
      h => externalClass.MessageReceived -= h); 

(私はイベントデリゲートMessageReceivedHandler呼ばれてきたように、あなたはクラスのDEFを提供していませんでした。)

public IObservable<MyMessage> DoAsynchronousCall(MyMessage message) 
{ 
    return Observable.Create<MyMessage>(o => 
    { 
     IObservable<MyMessage> result = 
      receivedMessages 
       .Where(m => m.Address == message.Address) 
       .Take(1); 

     IObservable<MyMessage> timeout = 
      Observable 
       .Timer(TimeSpan.FromSeconds(10.0)) 
       .Select(x => (MyMessage)null); 

     IDisposable subscription = 
      Observable 
       .Amb(result, timeout) 
       .Subscribe(o); 

     externalClass.Send(message); 

     return subscription; 
    }); 
} 

result観測可能である:今、あなたはDoAsynchronousToSynchronousCallとして再定義することができます現在のmessage.Addressのためにフィルタリングされた。

obserbleableは、コールに完了するのにTimeSpan.FromSeconds(10.0)よりも長くかかる場合に返されるデフォルト値です。

最後subscriptionresult又はtimeoutの最初の値を生成し、その結果をサブスクライブするかを決定するためにObservable.Amb(...)を使用します。私はBar!が印刷結果を得る...

public class ExternalClass 
{ 
    public event MessageReceivedHandler MessageReceived; 
    public void Send(MyMessage message) 
    { 
     this.MessageReceived(new MyMessage() 
     { 
      Address = message.Address, 
      Data = message.Data + "!" 
     }); 
    } 
} 

DoAsynchronousCall(new MyMessage() { Address = "Foo", Data = "Bar" }) 
    .Subscribe(response => Console.WriteLine(response.Data)); 

をので、私はこのようなExternalClassの簡単な定義を作る場合:だから今

は、あなたがこれを行うことができ、これを呼び出すためにコンソールで。

あなたはあなたがこれを行うことができます処理したいメッセージの全体の束がある場合:

var messagesToSend = new List<MyMessage>(); 

/* populate `messagesToSend` */ 

var query = 
    from message in messagesToSend.ToObservable() 
    from response in DoAsynchronousCall(message) 
    select new 
    { 
     message, 
     response 
    }; 

query 
    .Subscribe(x => 
    { 
     /* Do something with each correctly paired 
      `x.message` & `x.response` 
     */ 
    }); 
関連する問題