2016-06-02 13 views
2

私はEFの非同期メソッドを使用してデータベースからデータをフェッチしています。ほとんどの場合、すべてが順調です。私は後半の数ObjectContextDisposed例外になってきた、と私は私の解決策が機能する理由として興味があります:ここでこれらの2つの非同期実装の違い

ObjectContextDisposedを投げた私の元のコードだった:ここ

public Task<List<string>> GetEventParameterMru(EventParameter parameter, int count = 20) 
{ 
    using (var repo = new ConfigurationRepository()) 
    { 
     return repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count)    
    } 
} 

は「doesnの私の新しいコードですトンスロー:

public async Task<List<string>> GetEventParameterMru(EventParameter parameter, int count = 20) 
{ 
    using (var repo = new ConfigurationRepository()) 
    { 
     var result = await repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count); 
     return result; 
    } 
} 

誰かが差があり、そしてなぜそれがどのような作品に私に説明してもらえますか?

ちょうどFYI、この方法のすべての私の用途では、私が呼んawait GetEventParameterMru()

おかげ

答えて

5

GetEventParameterMRUは明らかにいくつかのデータを取得するためにTaskを開始する方法です。したがって、repoのすべての操作が完了する前にGetEventParameterMRUが返されます。

どちらのバージョンのコードも、try/finallyブロックに変換されたusingステートメントを使用します。 finallyブロックでは、repoとなり、になります。

最初のバージョンでは、GetEventParameterMRU(タスクの開始)を呼び出した後にimmediatlyを返します。これは、repoが即時に処理され、Taskrepoで実行されていることを意味します。したがって、このTaskはあなたがawaitを使用する第二版では、あなたの

説明ObjectDisposedException


を受けるrepoアクセスしたとき。そのためのコンパイラは、あなたの全メソッドを状態マシンに変換します。このメソッドは、awaitステートメントで呼び出し元に制御を返しますが、finallyブロックを渡さずにブロックを返します。
Taskが完了すると、awaitステートメントの後にメソッドの実行が続行されます。
したがって、repoは、Taskが完了したときにのみとなります。です。だから、あなたはObjectDisposedExceptionを得ていない。

+0

ありがとう、これは非常に明確かつ簡潔でした。 – Simon

2

後は、最初のコードレビューで私の理解である:最初の一

Async実装ではありませんが、最後にTask is executed(呼び出し元によって行われたものとしますが、それを開始するメソッド-GetEventParameterMRUであってもtrueを保持している場合)、からタスクが返されます。 ibleそのレポは、その時点で配置されているが、それでも操作は上の2つ目でこれの例外

あり、それはそれはするまで、次の完了しない限り、UI /呼び出しスレッドを解放した場合でも、ありません。

await repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count) 

それは完全にObjectContextDisposed問題

+0

なぜ、 'repo.Dispose();'が第2の呼び出しで呼び出されないのですか?私はそれがかなり確信しています。非同期であるため、コードは「削除」されません。 – Maarten

+0

@Maarten常に呼び出されます。問題はそれが呼び出されるときです。 – Euphoric

+0

@ユーフォリック私はそれを知っています、それはこの答えは、2番目の例では、Disposeメソッドが呼び出されていないことを示唆しています。 – Maarten

0

を避けるため、repo.Dispose()を呼び出し、しません明示的にこれをキャプチャん待っている間、私は、これが最初のコードが明示的に現在のSynchronizationContextをキャプチャないとしなければならないと考えています。

さらにいくつかの読書:

https://msdn.microsoft.com/en-us/magazine/gg598924.aspx

+0

を呼び出すことはありません、それはなっオブジェクトうさまだ使用中に処分されました –

1

私はあなたのためにそれらを翻訳してみましょう:

まず1:

Create repository 
Start GetEventParameterMRU on repository as Task 
Dispose repository 
return Task, that is still working with repository 

第二1:

Create repository 
Start GetEventParameterMRU on repository as Task 
Wait for Task to finish to get result 
Dispose repository 
return result 

あなたが見ることができるように、ここでの問題は非常に明確です。

関連する問題