文档清楚地表明他们关注的情况是
延续链中的一个任务分配给一个变量,另一个任务读取该变量
(重点是我。)这不是对象生命周期的问题,而是对象身份的问题。
以Hilo project 为例,密切关注decoder 变量(即shared_ptr<BitmapDecoder^>):
task<InMemoryRandomAccessStream^> ThumbnailGenerator::CreateThumbnailFromPictureFileAsync(
StorageFile^ sourceFile,
unsigned int thumbSize)
{
(void)thumbSize; // Unused parameter
auto decoder = make_shared<BitmapDecoder^>(nullptr);
auto pixelProvider = make_shared<PixelDataProvider^>(nullptr);
auto resizedImageStream = ref new InMemoryRandomAccessStream();
auto createThumbnail = create_task(
sourceFile->GetThumbnailAsync(
ThumbnailMode::PicturesView,
ThumbnailSize));
return createThumbnail.then([](StorageItemThumbnail^ thumbnail)
{
IRandomAccessStream^ imageFileStream =
static_cast<IRandomAccessStream^>(thumbnail);
return BitmapDecoder::CreateAsync(imageFileStream);
}).then([decoder](BitmapDecoder^ createdDecoder)
{
(*decoder) = createdDecoder;
return createdDecoder->GetPixelDataAsync(
BitmapPixelFormat::Rgba8,
BitmapAlphaMode::Straight,
ref new BitmapTransform(),
ExifOrientationMode::IgnoreExifOrientation,
ColorManagementMode::ColorManageToSRgb);
}).then([pixelProvider, resizedImageStream](PixelDataProvider^ provider)
{
(*pixelProvider) = provider;
return BitmapEncoder::CreateAsync(
BitmapEncoder::JpegEncoderId,
resizedImageStream);
}).then([pixelProvider, decoder](BitmapEncoder^ createdEncoder)
{
createdEncoder->SetPixelData(BitmapPixelFormat::Rgba8,
BitmapAlphaMode::Straight,
(*decoder)->PixelWidth,
(*decoder)->PixelHeight,
(*decoder)->DpiX,
(*decoder)->DpiY,
(*pixelProvider)->DetachPixelData());
return createdEncoder->FlushAsync();
}).then([resizedImageStream]
{
resizedImageStream->Seek(0);
return resizedImageStream;
});
}
decoder 变量首先在延续之外定义,因为在多个延续中都需要它。此时,它的值为空。它是在第二个延续中获取和设置的,并且该对象的属性(PixelWidth 等)在第四个延续中使用。
如果您将decoder 定义为BitmapDecoder^,将其设置为nullptr,然后在第二个延续中为其分配一个值,则该更改不会传播到后续延续,因为更改无法反映回到初始句柄(lambda 复制了句柄,本质上是复制内存地址 0x00000000)。
为了更新原始版本(和后续引用),您需要额外的间接(例如BitmapDecoder^*)。 shared_ptr<BitmapDecoder^> 就是这样一种间接方式,它很有用,因为您不需要像使用原始指针那样管理指针的生命周期,这就是文档中推荐它的原因。
在其他情况下,捕获Object^ 就足够了,例如,如果我在我的延续之外创建了一个TextBlock^,并在第一个延续中设置它的一些属性,并在后续延续中读取一些其他属性。在这种情况下,所有句柄都指向同一个底层对象,并且没有继续尝试覆盖对象本身的标识。 (但是,正如最初提到的,这不是文档所指的用例。)