c# - 在延续中使用一个对象,确保它在你需要它之​​前不会被释放

在 Xamarin.iOS 应用程序中,出于各种原因我们不能使用 async/await。因此,我们正在使用 Task.ContinueWith。问题是我们在延续中依赖的对象在调用延续之前就被释放了。

using (UIImage image = // Somehow get the image)
{
    DoSomethingWith(image);
}

void DoSomethingWithImage(UIImage image)
{
    UploadImageAsync(image).ContinueWith(t =>
    {
        // Image has been disposed by this point.
        DisplayResult(t.Result, image);
    });
}

我很想知道如何处理上述案例。我考虑过的选项:

  • 删除 using block ,并让 image 超出范围。这将是一个坏主意,因为 UIImage 可能会非常大。
  • 移除using,并在continuation中调用Dispose()。这感觉很容易出错,因为无论哪里存在这样的代码,您都会将对象放置在远离其创建位置的地方。
  • 将对 DoSomethingWithImage() 的调用包装在 Task.Run(() => DoSomethingWithImage(image)).ContinueWith(t => image.Dispose())。所以你有一个延续中的延续。对于这种情况,这感觉过于复杂。
  • 还有其他我忽略的选项吗?

最佳答案

首先,这是一个很好的问题。根据上述选项,我认为您必须更改 angel。

在您当前的实现中,UIImage 的范围与 DoSomethingWith 方法密切相关。换句话说,检索到的图像仅在该方法内部使用。我可以看到两种不同的方式,这将如何演变:

  1. 引入DoSomethingElseWith方法
  2. 摆脱 DoSomethingWith 并“内联” UploadImageDisplayResult

无论哪种方式,您最终都会在 using block 中包含多个方法。这将表明 UIImage 的清理不是方法的责任。在正常情况下,您会通过 await 最后一个并让 using block 完成其工作来完成此操作,对吗?如果您不能等待它,那么继续的最明显选择是使用 ContinueWith。 (其他: TaskFactory.ContinueWhenAll, TaskFactory.ContinueWhenAny, Task.WhenAll, Task.WhenAny, for further info ) .

UIImage image = RetrieveImage();
var uploadJob = UploadImage(image);
var displayJob = uploadJob.ContinueWith((t => DisplayResult(t.Result, image)).Unwrap();
var disposeJob = displayJob.ContinueWith(_ => image.Dispose());

或者,您可以使用一些短信号机制(同步原语)来指示最后一个异步操作何时完成,例如 AutoResetEventCountdownEventTaskCompliitionSource.

您的第三个选择可能是使用 TPL Dataflow 。有了它,您可以将小块组合在一起,并使用 Completion 启动处置作为您的最后一个操作。

https://stackoverflow.com/questions/62494305/

相关文章:

reactjs - 使用 enzyme 设置 redux 连接的 react 组件的状态

c# - 使用 MVC 从数据主体调用 post API

c# - SSIS - 文件存在性检查未正确控制包任务流

visual-studio-code - VS Code 中的 Prettier 不断突破界限

react-native - 如何使用 RNFetchBlob.fetch 和 react-nati

php - 模拟 Laravel 缓存助手

javascript - 如何使 React 组件更可重用?

swift - Xcode 预览不适用于通用 View

.net - PubSub 上的 Http 400 推送到云运行

mysql - 使用python中的线程在Mysql上同时运行多个查询