StorageFolder.CreateFolderAsync 中的奇怪行为
strange behaviour in StorageFolder.CreateFolderAsync
我正在为 windows 商店应用程序做一些事情,这是一个通用应用程序项目,我正在 Windows 8.1 笔记本和 windows 8.1 Surface Pro 3 上进行调试.
我正在尝试在 ApplicationData.Current.LocalFolder 中创建一些嵌套文件夹。
从主屏幕的构造函数中,我调用
CacheManager.InitializeOfflineFiles().Wait();
CacheManager.InitializeOfflineFiles() 的代码是
public static async Task InitializeOfflineFiles()
{
try
{
StorageFolder s1 = await ApplicationData.Current.LocalFolder.CreateFolderAsync("one", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder one");
StorageFolder s2 = await s1.CreateFolderAsync("two", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder two");
StorageFolder s3 = await s2.CreateFolderAsync("three", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder three");
StorageFolder s4 = await s3.CreateFolderAsync("four", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder four");
}
catch (Exception e)
{
Debug.WriteLine("Windows doesn't love you. Exception: " + e.Message);
}
}
当我调试它时,它并没有通过创建文件夹 "two"。没有异常记录,什么都没有。此外,当我 运行 这没有调试 (Ctrl + F5) 时,结果相同,只有 dir "one/two" 在本地存储中创建。
这是对异步编程的误解吗?
这个:
CacheManager.InitializeOfflineFiles().Wait();
导致您的应用死锁。这就是您看到 "hanging" 行为的原因。奇怪的是,您似乎看到正在创建文件夹 1 和 2,因为我认为在执行第一个 await
时这应该会死锁。
这就是你 shouldn't block on async code 的原因。
由于构造函数不能异步,请改用 "Initialize Pattern" (or other known async initalization patterns) 来执行您的异步代码:
public Task InitializeAsync()
{
return InitializeOfflineFilesAsync()
}
然后从您的代码中,从 async
上下文方法调用它,也许是 事件处理程序:
public async void SomeButtonClickEventHandler()
{
await InitializeAsync();
}
故事的寓意是,不要通过构造函数调用异步方法。
事实证明,我可以从构造函数中调用异步方法。
在构造函数中:
var task = Task.Run(async () =>
{
return await CacheManagerInitializeOfflineFiles();
});
string dummy = task.Result;
相同class中的方法调用创建存储目录的异步方法:
private async Task<string> CacheManagerInitializeOfflineFiles()
{
await CacheManager.InitializeOfflineFiles();
return "done";
}
我真的不想放一个按钮 "initialize application",那将是糟糕的设计:)
要避免死锁,试试这个:
StorageFolder s1 = await ApplicationData.Current.LocalFolder.CreateFolderAsync("one", CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);
我正在为 windows 商店应用程序做一些事情,这是一个通用应用程序项目,我正在 Windows 8.1 笔记本和 windows 8.1 Surface Pro 3 上进行调试.
我正在尝试在 ApplicationData.Current.LocalFolder 中创建一些嵌套文件夹。 从主屏幕的构造函数中,我调用
CacheManager.InitializeOfflineFiles().Wait();
CacheManager.InitializeOfflineFiles() 的代码是
public static async Task InitializeOfflineFiles()
{
try
{
StorageFolder s1 = await ApplicationData.Current.LocalFolder.CreateFolderAsync("one", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder one");
StorageFolder s2 = await s1.CreateFolderAsync("two", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder two");
StorageFolder s3 = await s2.CreateFolderAsync("three", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder three");
StorageFolder s4 = await s3.CreateFolderAsync("four", CreationCollisionOption.OpenIfExists);
Debug.WriteLine("Created folder four");
}
catch (Exception e)
{
Debug.WriteLine("Windows doesn't love you. Exception: " + e.Message);
}
}
当我调试它时,它并没有通过创建文件夹 "two"。没有异常记录,什么都没有。此外,当我 运行 这没有调试 (Ctrl + F5) 时,结果相同,只有 dir "one/two" 在本地存储中创建。
这是对异步编程的误解吗?
这个:
CacheManager.InitializeOfflineFiles().Wait();
导致您的应用死锁。这就是您看到 "hanging" 行为的原因。奇怪的是,您似乎看到正在创建文件夹 1 和 2,因为我认为在执行第一个 await
时这应该会死锁。
这就是你 shouldn't block on async code 的原因。
由于构造函数不能异步,请改用 "Initialize Pattern" (or other known async initalization patterns) 来执行您的异步代码:
public Task InitializeAsync()
{
return InitializeOfflineFilesAsync()
}
然后从您的代码中,从 async
上下文方法调用它,也许是 事件处理程序:
public async void SomeButtonClickEventHandler()
{
await InitializeAsync();
}
故事的寓意是,不要通过构造函数调用异步方法。
事实证明,我可以从构造函数中调用异步方法。 在构造函数中:
var task = Task.Run(async () =>
{
return await CacheManagerInitializeOfflineFiles();
});
string dummy = task.Result;
相同class中的方法调用创建存储目录的异步方法:
private async Task<string> CacheManagerInitializeOfflineFiles()
{
await CacheManager.InitializeOfflineFiles();
return "done";
}
我真的不想放一个按钮 "initialize application",那将是糟糕的设计:)
要避免死锁,试试这个:
StorageFolder s1 = await ApplicationData.Current.LocalFolder.CreateFolderAsync("one", CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);