質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

1854閲覧

【c#】いい設計の質問

syogakusya

総合スコア67

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/10/21 04:19

編集2016/10/21 04:22

###質問

3パターンの処理ABCがクライアントによって要求され、それをキューで1つずつ処理するプログラムを書きます。
Aはファイル書き込み、Bはデータベース書き込み、CはWEBAPIの実行です。
処理すべき要求の一つ一つをオブジェクトとみなし、要求を表す抽象クラスWhatToDoと、その派生クラスA,B,Cを実装しています。
A,B,Cクラスでの処理に必要なデータとクライアントへの応答手段は全てコンストラクタで渡しているものとします。(引数を渡すところは省略します。)

ここからが問題で、一部要求についてクライアントに応答を返すのですが、ファイル書き込み要求(A)は応答を返さず、データベース書き込み要求(B)は同期処理後にすぐ応答を返し、WEBAPI実行要求(C)はWEBAPIからのレスポンスを受け取った後に応答を行います。
このCを要求したクライアントへの応答をどう実現するかで悩んでいます。
以下がコードになります。
Cの応答以外は全て実現されています。

C#

1 2Queue<WhatToDo> queue = new Queue<WhatToDo>(); 3 4void client_RequestedA() 56 // 書き込み先や書き込み内容を渡している 7 var a = new A(//...); 8 queue.Enqueue(a); 910 11void client_RequestedB() 1213 // クライアントへの応答手段、接続先や書き込み内容を渡している 14 var b = new B(//...); 15 queue.Enqueue(b); 1617 18void client_RequestedC() 1920 // クライアントへの応答手段、apiのurlやパラメータを渡している 21 var c = new C(//...); 22 queue.Enqueue(c); 2324 25void myQueueTimer_Elasped() 26{ 27 // キューから要求を引っ張りだして処理 28 var whatToDo = queue.Dequeue(); 29 whatToDo.Do(); 30} 31 32void webAPI_Responded() 33{ 34 //// ここで何かするべきか? 35} 36 37class WhatToDo 38{ 39 // 各要求に対する具体的な処理はDoメソッドで行う 40 public abstract void Do(); 41} 42 43class A : WhatToDo 44{ 45 public override void Do() 46 { 47 // ファイル書き込み 48 //... 49 } 50} 51 52class B : WhatToDo 53{ 54 public override void Do() 55 { 56 // DB書き込み 57 //... 58 // クライアントに返信 59 //... 60 } 61} 62 63class C : WhatToDo 64{ 65 public override void Do() 66 { 67 // WEBAPIにリクエスト 68 //... 69 } 70}

ご意見をお聞かせください。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

AとBが同期処理なのに、Cだけ非同期なので全部を同じように処理するのが難しいということでよろしいでしょうか?
以下はそう解釈した上での回答になります。

(私の)考えられる方法は二通りで、AとBを非同期の処理として実装するか、Cを同期処理として実装するかのどちらかです。
要するに全部同期処理にするか、全部非同期処理にするかです。

Cを同期処理にするのは簡単で、Doの中でレスポンスがあるまで待つだけです。
待つ方法の実装は様々な方法がありますがC#標準のWeb系の関数を使っているなら多分それらにもあるはずです。

もうひとつの全部非同期として実装するパターンは、
全部のレスポンス(返り値)をTask<返り値型>にしてしまってTask.Resultで受け取るのが一番簡単かもしれませんね。
How to: Return a Value from a Task

投稿2016/10/21 04:46

編集2016/10/21 04:50
ishi9

総合スコア1294

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syogakusya

2016/10/21 04:54

すみません。業務の話なので代わりに例として出したのですが、実のところはCはWEBAPIではなく通信インターフェースによる通信で、server_Completedメソッドが完全な別スレッドで呼ばれます。(いつ呼び出されるかは全く予測不可能です。) そのためTaskなどの非同期処理を使って待機することはできません。 例が悪く申し訳ございませんでした。
ishi9

2016/10/21 07:09

自前の処理であっても、待つことは可能だと思いますよ。 それこそ、フラグが立つまでスピンロックで待ち続けるってだけでも一応成り立ちますし (まぁ業務でそんな実装するかって言われたらちょっとあれですが)
ishi9

2016/10/21 10:00 編集

この辺参考になるかもしれません。 スレッドの特定の処理が終わるまでメインスレッドをブロックして待機する https://www.ipentec.com/document/document.aspx?page=csharp-wait-thread-proc-block 非同期処理関連のmsdnの資料読んでみた2 http://komaken.me/blog/2014/02/08/c%E9%9D%9E%E5%90%8C%E6%9C%9F%E5%87%A6%E7%90%86%E9%96%A2%E9%80%A3%E3%81%AEmsdn%E3%81%AE%E8%B3%87%E6%96%99%E8%AA%AD%E3%82%93%E3%81%A7%E3%81%BF%E3%81%9F2/
guest

0

レスポンスを返す対象を与えておけばいいです。もちろんインスタンスでいいとおもいます。

しかし内容から考えると、関数を渡す方法をお勧めします。

Queue<Action<>> queue = new Queue<Action<>>(); void client_RequestedA() { // 書き込み先や書き込み内容を渡している var a = new A(//...); queue.Enqueue(a.Do); // 関数の型があればいいのでインターフェイスは不要 } void client_RequestedB() { // クライアントへの応答手段、接続先や書き込み内容を渡している var b = new B(//...); queue.Enqueue(b.Do); } void client_RequestedC() { // クライアントへの応答手段、apiのurlやパラメータを渡している var c = new C(//...); queue.Enqueue(c.Do); } void myQueueTimer_Elasped() { // キューから要求を引っ張りだして処理 var whatToDo = queue.Dequeue(); whatToDo.Do(); } class A { public override void Do() { // ファイル書き込み //... } } class B { public override void Do() { // DB書き込み //... // クライアントに返信 //... } } class C { public override void Do() { var res = .... // WEBAPIにリクエスト webAPI_Responded(res); } public webAPI_Responded(Response res) //Responseは架空の型 { // レスポンスの処理 } }

コンパイルしていないので、細かい点間違えてると思いますがおおむねこのような書き方ができます。

投稿2016/10/21 05:24

編集2016/10/21 07:54
iwamoto_takaaki

総合スコア2883

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問