2

RIA サービスで使用されるイベント非同期プログラミング モデルをタスクにラップしようとしています。

TaskCompletionSource を使用する標準的な方法に従い、次の拡張メソッドを実装しました。

public static Task<IEnumerable<T>> LoadAsync<T>(this DomainContext source, EntityQuery<T> query) where T : Entity
{
    TaskCompletionSource<IEnumerable<T>> taskCompletionSource = new TaskCompletionSource<IEnumerable<T>>();

    source.Load(
        query,
        loadOperation =>
        {
            if (loadOperation.HasError && !loadOperation.IsErrorHandled)
            {
                taskCompletionSource.TrySetException(loadOperation.Error);
                loadOperation.MarkErrorAsHandled();
            }
            else if (loadOperation.IsCanceled)
            {
                taskCompletionSource.TrySetCanceled();
            }
            else
            {
                taskCompletionSource.TrySetResult(loadOperation.Entities);
            }
        },
        null);

    return taskCompletionSource.Task;
}

次に、これを次のように使用します。

var task = _context.LoadAsync(_context.GetPlayersQuery());
task.Start();
task.Result;

ただし、問題は、「約束スタイルのタスクで Start が呼び出されない可能性がある」という InvalidOperationException が発生することです。タスクを開始しないようにしましたが、loadOperation コールバックが起動しません。

ここで私が間違っていることを誰かが見ることができますか?

前もって感謝します

4

3 に答える 3

1

問題は解決しました。内部では、DomainContext.Load() メソッドはすでに非同期で動作しています。すでに非同期のメソッドをタスクにラップしようとすると、競合が発生したに違いありません。

ただし、以下のコードで EAP に正しく従ったとしても、「promise スタイルのタスクで start を呼び出すことはできません」という InvalidOperationException が引き続き発生します。

public static Task<IEnumerable<T>> LoadAsync<T>(this DomainContext source, EntityQuery<T> query) where T : Entity
{
    TaskCompletionSource<IEnumerable<T>> taskCompletionSource = new TaskCompletionSource<IEnumerable<T>>();

    var loadOperation = source.Load(query);
    loadOperation.Completed += (obj, args) =>
    {
        if (loadOperation.HasError && !loadOperation.IsErrorHandled)
        {
            taskCompletionSource.TrySetException(loadOperation.Error);
            loadOperation.MarkErrorAsHandled();
        }
        else if (loadOperation.IsCanceled)
        {
            taskCompletionSource.TrySetCanceled();
        }
        else
        {
            taskCompletionSource.TrySetResult(loadOperation.Entities);
        }
    };

    return taskCompletionSource.Task;
}
于 2012-05-05T00:34:46.397 に答える
0

使ってみて

task.ContinuewWith(Action<Task<T>> continuation)

task.Start を使用しているときに私もその例外を受け取ったので、それは私にとってはうまくいきました

于 2012-05-16T00:30:53.933 に答える
0

代わりにこれを試してください

var result = await _context.LoadAsync(_context.GetPlayersQuery());
于 2012-05-04T02:26:49.177 に答える