我正在使用EF的异步方法从数据库中获取数据。大部分时间都很好。我最近遇到了一些ObjectContextDisposed异常,我很好奇为什么我的解决方案有效:
以下是投放ObjectContextDisposed
的原始代码:
public Task<List<string>> GetEventParameterMru(EventParameter parameter, int count = 20)
{
using (var repo = new ConfigurationRepository())
{
return repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count)
}
}
这是我的新代码,不会抛出:
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;
}
}
有人可以向我解释一下有什么区别,为什么会有效?
仅供参考,在我使用此方法的所有用法中,我致电await GetEventParameterMru()
由于
答案 0 :(得分:5)
GetEventParameterMRU
显然是一种启动Task
来检索某些数据的方法。因此,在GetEventParameterMRU
的所有操作都已完成之前,repo
会返回。
两个版本的代码都使用using
语句,该语句被转换为try/finally
块。在finally
区块中,repo
将处置。
在您的第一个版本中,在调用GetEventParameterMRU
(启动任务)后返回 immediatly 。这意味着repo
在使用Task
的{{1}}仍在运行时会立即处理。因此,当repo
访问Task
时,您会收到
的ObjectDisposedException
在第二个版本中,您使用repo
。因此,编译器将您的整个方法转换为状态机。该方法在await
语句处将控制权返回给其调用者,但没有传递await
块。
finally
完成后,在Task
语句后继续执行您的方法
因此await
仅在repo
完成时处理。所以你没有得到Task
。
答案 1 :(得分:2)
以下是我对初始代码审核的理解:
在第一个中,Async
实施不是using block
,但最后repo.Dispose()
仍会从最终调用Task is executed
的{{1}}返回一个任务(假设它由调用者完成,但即使对于方法 - GetEventParameterMRU
启动它也是如此),在那个时间处置repo是非常可行的,但仍然是操作,因此异常< / p>
在第二个问题中,情况并非如此,即使它已经释放了UI /调用线程,直到并且除非完成以下操作:
await repo.GetEventParameterMRU(_CurrentWorkpack, parameter, count)
它不会调用repo.Dispose()
,从而完全避免ObjectContextDisposed
问题
答案 2 :(得分:1)
让我为你翻译一下:
第一个:
Create repository
Start GetEventParameterMRU on repository as Task
Dispose repository
return Task, that is still working with repository
第二个:
Create repository
Start GetEventParameterMRU on repository as Task
Wait for Task to finish to get result
Dispose repository
return result
正如你所看到的,问题在这里很清楚。
答案 3 :(得分:0)
我认为这与第一个没有显式捕获当前SynchronizationContext的代码有关,而等待DOES明确地捕获它。
进一步阅读: