4

当在不同的线程上多次调用 Windows.Storage.StorageFolder.GetFolderFromPathAsync 时,我收到 ArgumentExceptions。这是重现该问题的测试:

[TestMethod]
public async Task ConcurrentGetFolderFromPath()
{
    List<Task> tasks = new List<Task>();
    for (int i = 0; i < 10; i++)
    {
        var task = Task.Run(async () =>
            {
                string localFolderPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
                //await Task.Yield();
                var folder = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(localFolderPath);
            });

        tasks.Add(task);
    }

    await Task.WhenAll(tasks);
}

这是我得到的例外:

System.ArgumentException: Value does not fall within the expected range.
Result StackTrace:  
    at Windows.Storage.StorageFolder.GetFolderFromPathAsync(String path)
    at PCLStorage.Test.FolderTests.<<ConcurrentGetFolderFromPath>b__53>d__55.MoveNext() in c:\git\pclstorage\test\PCLStorage.Test\FolderTests.cs:line 205

当我自己运行它时,测试始终失败,但当我与其他PCL 存储测试一起运行时,它通常会通过。

我在这里做错了吗?GetFolderFromPathAsync 或我正在使用的任何其他 API 是否只应该在 UI 线程中使用?或者这可能是 WinRT 存储 API 中的错误?

4

1 回答 1

0

好的,所以这里的问题是Task.Run它处理的方式之一async delegates。基本上,当你说:

Task.Run(async () => ...)

它返回给您的不是Task您期望的普通简。它返回包装在另一个任务中的任务,即一个任务。因此,为了获得您正在寻找的任务(检索 StorageFolderawait的任务),您需要外部任务。您只需在将其添加到tasks列表时进行更改即可:

tasks.Add(await task);

现在,还有第二个问题。您可能同时从同一个文件夹中进行大量读取。这可能会导致一些AccessExceptions. 也可能不是。这样做时我会小心的。

我在 WinRT 的单元测试中进行文件读/写时遇到问题。幸运的是,我正在使用 Mvvm(通过 Mvvm Light)并将我的本地存储访问包装在Controller. 这使我能够做的是编写一个LocalStorageController仅用于单元测试的程序,它允许我对内存中的文件系统执行所有 IO(基本上是一个简单的Dictionary<string, byte[]>. 这确实使测试复杂的文件树变得更加困难,但您也可以使用不同的数据结构(例如实际的Tree)来对文件系统进行建模。

无论如何,我希望这会有所帮助。不过,我很抱歉,您问了这么久。快乐编码!

于 2013-07-18T22:01:41.537 回答