如何使用async/await异步创建DispatcherObject



很明显,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对象中获取所有需要的数据,并在没有线程关联的情况下传递回一个普通对象。但如果有人知道更好的方法,请告诉我。

您总是回到同一个上下文中,但并非所有上下文都绑定到一个线程。值得注意的是,线程池上下文将所有线程池线程视为相等。

但我不认为这是这里的具体问题——您使用的是Task.Run(),它旨在在线程池中运行代码。因此,即使await将所有内容都切换回UI上下文,也没关系,因为您在线程池中显式地运行了一些代码。

这是一个有趣的问题,因为(正如您正确指出的)GifBitmapDecoder继承自DispatcherObject。这意味着它的实现不允许任何线程调用其操作。

要使用任何DispatcherObject,您应该通过其Dispatcher属性进行调用。返回的Dispatcher对象使您可以通过InvokeAsync:以与其内部线程模型兼容的方式针对真实对象调度委托

var decoder = new GifBitmapDecoder(...);
var operation = decoder.Dispatcher.InvokeAsync(() => { }); // Do things here!

这种模式不是返回TPLTask而是返回DispatcherOperation(可能是因为它早于TPL)。这个类似任务的对象可以让您检查操作的状态并获得任何结果。它也是可用的,这意味着你可以像使用TPLTask:一样使用await

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();
}

Task.Run()调度到线程池,因此您的GifBitmapDecoder是在另一个线程上创建的。

OpenFileTask正在返回一个task<GifBitMapDecoder>。您可能需要

Task <GifBitMapDecoder> t = OpenFileTask();

Fdecoder = t.result; //Returns the GifBitMapDecoder object.

虽然对异步的东西不太了解,但可能和你的一样

来源:C#5.0。

最新更新