7

現在、かなりの量の既存の同期コードを WinRT に移植しようとしています。

この一環として、一部の操作が同期することを期待している既存のコードで問題が発生しています (ファイル I/O など)。

この既存のコードを WinRT 内の IAsyncOperation スタイル API で動作するように適合させるために、次のような拡張メソッドで IAsyncOperation をラップする手法を使用しました。

namespace Cirrious.MvvmCross.Plugins.File.WinRT
{
    public static class WinRTExtensionMethods
    {
        public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
        {
            var task = operation.AsTask();
            task.Wait();
            if (task.Exception != null)
            {
                // TODO - is this correct?
                throw task.Exception.InnerException;
            }

            return task.Result;
        }
    }
}

MvvmCross WinRT ExtensionMethodsから- 同様の方法でIAsyncAction

これらのラッパーは機能しているようで、次のAsyncような同期コードでメソッドを使用できます。

    public IEnumerable<string> GetFilesIn(string folderPath)
    {
        var folder = StorageFolder.GetFolderFromPathAsync(ToFullPath(folderPath)).Await();
        var files = folder.GetFilesAsync().Await();
        return files.Select(x => x.Name);
    }

これは実際には WinRT の精神に沿ったものではないことは理解しています。しかし、これらのメソッドは通常、そもそもバックグラウンド スレッドでのみ呼び出されると予想しています。そして、コードをクロスプラットフォーム互換にすることを目標にこれを書いています。これには、await-async をまだサポートしていないプラットフォームや、まだジャンプする準備ができていない開発者も含まれます。

ですから...問題は、このタイプのコードを使用することで、どのようなリスクが発生するのでしょうか?

2 番目の質問として、ファイル I/O などの分野でコードを再利用するためのより良い方法はありますか?

4

3 に答える 3

3

まず、あなたの方法は次のように書き直すことができると思います:

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    return operation.AsTask().Result;
}

Resultタスクがまだ終了していない場合、呼び出しは同期的に待機します。AgreggateExceptionそして、失敗した場合はスローします。InnerException例外のスタックトレースを上書きするため、あなたのようにスローするのは悪い考えだと思います。

Wait()あなたの実際の質問に関しては、非同期コードと一緒に使用することの最大の危険はデッドロックだと思います。UI スレッドで内部的awaitに使用する操作を開始し、同じスレッドで使用して待機するとWait()、デッドロックが発生します。

これは、UI スレッドを使用していない場合はそれほど重要ではありませんが、アイデアWait()全体に反するため、可能であれば回避する必要があります。async

于 2012-05-20T00:05:01.017 に答える
2

私はついにこれに答えるつもりです....

そして答えはあなたが本当にそれをすることができないということです。

他の回答で提案されているよりクリーンなメソッドのいくつかを使用しようとしても、ブロックしないことが約束されているスレッドでコードを実行しようとすると、最終的に例外が発生します-たとえば、UIスレッドで実行しようとするとまたはスレッドプールスレッド上。

だから...答えは、それが何らかの方法で非同期になるように、単にそのレガシーコードを再設計する必要があるということです!

于 2012-10-09T15:21:27.320 に答える
2

これをしない正当な理由はたくさんあります。たとえば、http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspxを参照してください。

ただし、それを行う場合は、次のように GetResults() メソッドを使用します

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation)
{
    try
    {
        return operation.GetResults();
    }
    finally
    {
        operation.Close();
    }
}  

svickが述べたように、IAsyncOperationをタスクにラップすることも機能しますが、効率は低下します。

于 2012-05-20T21:06:08.530 に答える