显然,async / await还有一些我不理解的东西。
以下代码有什么问题?它在异步任务中创建FDecoder
对象。但在那之后,每当我尝试访问FDecoder字段时,我都会收到一个InvalidOperation异常,声明该对象归另一个线程所有。我认为这是一个很酷的事情,等待,我得到的结果回到调用线程......?
//could take very long for image from web
private Task<GifBitmapDecoder> OpenFileTask(string filename, bool forceReload = false)
{
return Task.Run(() =>
{
return new GifBitmapDecoder(new Uri(filename, UriKind.RelativeOrAbsolute), forceReload ? BitmapCreateOptions.IgnoreImageCache : BitmapCreateOptions.None, BitmapCacheOption.Default);
});
}
GifBitmapDecoder FDecoder;
public async void OpenFileAsync(string filename, bool forceReload = false)
{
FDecoder = await OpenFileTask(filename, forceReload);
OpenCompleted(); // do stuff with FDecoder field, throws invalid thread exception
}
修改
好的,我发现的是Task创建的实际GifBitmapDecoder对象是DispatcherObject,它具有线程关联性。这是主要问题......似乎唯一的方法是从异步任务中的Dispatcher对象中获取所有需要的数据,并传回一个没有线程关联的普通对象。但如果有人知道更好的方法,请告诉我。
答案 0 :(得分:2)
您总是回到同一个上下文,但并非所有上下文都绑定到单个线程。值得注意的是,线程池上下文将所有线程池线程视为相等。
但我认为这不是具体问题 - 您使用Task.Run()
来表示在线程池中运行代码。因此,即使您的await
将所有内容都切换回UI上下文,也无关紧要,因为您在线程池中显式地运行了一些代码。
答案 1 :(得分:1)
这是一个有趣的问题,因为(正如你正确指出的那样)GifBitmapDecoder
继承自DispatcherObject
。这意味着它有一个实现,它不允许任何线程调用它的操作。
要使用任何DispatcherObject
,您应该通过其Dispatcher
属性进行调用。返回的Dispatcher
对象允许您通过InvokeAsync
以与内部线程模型兼容的方式为真实对象安排委托:
var decoder = new GifBitmapDecoder(...);
var operation = decoder.Dispatcher.InvokeAsync(() => { }); // Do things here!
这种模式,而不是返回TPL Task
返回DispatcherOperation
(大概是因为它早于TPL)。这个类似任务的对象允许您检查操作的状态并获得任何结果。它也是等待的,这意味着您可以像{TPL await
一样使用Task
:
await decoder.Dispatcher.InvokeAsync(() => { });
在您的具体问题中,您应该在OpenCompleted()
方法中使用此模式。您可能希望将其设为OnCompletedAsync()
并返回Task
以使您能够捕获连续的UI同步上下文,并让TPL处理从Dispatcher
到UI的编组调用线程。
public async void OpenFileAsync(string filename, bool forceReload = false)
{
FDecoder = await OpenFileTask(filename, forceReload);
await OpenCompletedAsync();
}
答案 2 :(得分:0)
Task.Run()
计划到线程池,因此您的GifBitmapDecoder
正在另一个线程上创建。
答案 3 :(得分:-1)
OpenFileTask正在返回task<GifBitMapDecoder>
。您可能需要
Task <GifBitMapDecoder> t = OpenFileTask();
Fdecoder = t.result; //Returns the GifBitMapDecoder object.
虽然对异步的东西知之甚少,但可能和你拥有的一样。
资料来源:C#5.0简而言之。