2013-07-24 4 views
5

私は最近、初めてasync(そして.Net 4.5本当に)を使用していました。私は、私が困惑しているものを見つけました。ネット上にあるVoidTaskResultクラスについての情報はあまりないので、何が起こっているのか誰かが考えているかどうかを調べるためにここに来ました。非同期メソッドに関連するVoidTaskResult型は何ですか?

私のコードは次のようなものです。明らかに、これはずっと単純化されている。基本的な考え方は、非同期型のプラグインメソッドを呼び出すことです。タスクが返された場合、非同期呼び出しからの戻り値はありません。彼らがタスク<>を返した場合、それがあります。彼らはどのタイプであるかを事前に知っているわけではないので、リフレクションを使用して結果のタイプを調べ、タイプがタイプ<>の場合はIsGenericTypeが真となり、ダイナミックタイプを使用して値を取得します。

実際のコードでは、リフレクションによってプラグインメソッドを呼び出しています。私はこれが私が見ている行動に違いをもたらすべきではないと思う。

// plugin method 
public Task yada() 
{ 
// stuff 
} 

public async void doYada() 
{ 
    Task task = yada(); 
    await task; 

    if (task.GetType().IsGenericType) 
    { 
    dynamic dynTask = task; 
    object result = dynTask.Result; 
    // do something with result 
    } 
} 

これは、上記のプラグインメソッドに適しています。 IsGenericTypeは(期待通りに)falseです。

あなたはほんの少しのプラグイン方式の宣言を変更する場合は、IsGenericTypeは現在、trueを返しとか休憩は:あなたがこれを行うと

public async Task yada() 
{ 
// stuff 
} 

、次の例外がライン(オブジェクト結果にスローされます= dynTask.Result;):タスクオブジェクトに掘る場合

RuntimeBinderException

、実際にタイプのように見えます。 VoidTaskResultは、ほとんど何も入っていないスレッド型の名前空間のプライベート型です。私は分別できない

public async void doYada() 
{ 
    Task task = yada(); 
    await task; 

    if (task.GetType().IsGenericType) 
    { 
    object result = task.GetType().GetProperty("Result").GetMethod.Invoke(task, new object[] { }); 
    // do something with result 
    } 
} 

このことは、もはやスローという意味で「成功」が、今は結果のタイプである「VoidTaskResult」:私は私の呼び出し元のコードを変更しようとした

VoidTaskResult task

と何かをする。

私はこのすべてのために本当の質問を定式化するのにも苦労していると付け加えるべきです。私の本当の疑問は、「VoidTaskResultとは何か?」「非同期メソッドを動的に呼び出すと、なぜこの奇妙なことが起こるのですか?場合によっては非同期型のプラグインメソッドをどのように呼び出すのですか?いずれにしても、私は、師の一人が光を放つことができるという希望で、これをそこに置いています。

答えて

9

これは、タスク(特にタスク補完ソース)に関するクラス階層が設計されているためです。

最初にオフ、Task<T>Taskに由来します。あなたはすでにそれに精通していると思います。

さらに、コードを実行するタスクのタイプをTaskまたはTask<T>にすることができます。たとえば、最初の例がTask.Runまたはその他のものを返す場合、実際のTaskオブジェクトが返されます。

TaskCompletionSource<T>がタスク階層とどのように対話するかを検討すると問題が発生します。TaskCompletionSource<T>は、コードを実行しないタスクを作成するために使用されますが、一部の操作が完了したという通知として機能します。たとえば、タイムアウト、I/Oラッパー、またはasyncメソッド。

には非ジェネリックTaskCompletionSourceタイプがありませんので、あなたは、戻り値(例えば、タイムアウトやasync Task方法)することなく、このような通知を持つようにしたい場合は、あなたは、いくつかのTためTaskCompletionSource<T>を作成し、Task<T>を返すことがあります。 asyncチームはasync Taskメソッドのを選択しなければならなかったので、タイプはVoidTaskResultでした。

通常これは問題ではありません。 Task<T>Taskに由来するため、値はTaskに変換され、誰もが(静的な世界では)満足しています。しかし、TaskCompletionSource<T>によって作成されたすべてのタスクは、実際にはタイプTask<T>であり、Taskではなく、リフレクション/ダイナミックコードで表示されます。

最終結果は、TaskのようにTask<VoidTaskResult>を扱わなければならないということです。しかし、VoidTaskResultは実装の詳細です。それは将来変更される可能性があります。

したがって実際には(実際の)戻り値ではなく、(宣言された)戻り値の型がyadaであることをお勧めします。これは、コンパイラが行うことをよりよく模倣します。

+0

なぜ非同期チームは非汎用TaskCompletionSourceを導入するのではなく、VoidTaskResultを導入しましたか? – Puppy

+0

@Puppy:それははるかに少ない仕事だったので私は疑う。非常置型の「TaskCompletionSource」を書くことはそれほど難しいことではありませんが、パブリックなAPIは解放される前に、他の「ゲート」を通過しなければなりません。セキュリティレビューなど –

関連する問題