10

Load() と Process() の 2 つのメソッドを持つクラスがあります。これらをバックグラウンド タスクとして個別に、または順番に実行できるようにしたいと考えています。ContinueWith() 構文が気に入っていますが、機能させることができません。続行するメソッドで Task パラメーターを取得する必要があり、最初のメソッドで Task パラメーターを取得できません。

ラムダ式を使用せずに実行したいのですが、ラムダ式を使用するか、メソッドの 1 つにタスク パラメーターを強制するか、3 つ目のメソッド LoadAndProcess() を作成するかのいずれかで行き詰まっていますか?

void Run()
{
    // doesn't work, but I'd like to do it
    //Task.Factory.StartNew(MethodNoArguments).ContinueWith(MethodNoArguments);

    Console.WriteLine("ContinueWith");
    Task.Factory.StartNew(MethodNoArguments).ContinueWith(MethodWithTaskArgument).Wait();

    Console.WriteLine("Lambda");
    Task.Factory.StartNew(() => { MethodNoArguments(); MethodNoArguments(); }).Wait();

    Console.WriteLine("ContinueWith Lambda");
    Task.Factory.StartNew(MethodNoArguments).ContinueWith(x => { 
            MethodNoArguments(); 
        }).Wait();
}

void MethodNoArguments()
{
    Console.WriteLine("MethodNoArguments()");
}

void MethodWithTaskArgument(Task t = null)
{
    Console.WriteLine("MethodWithTaskArgument()");
}
4

2 に答える 2

19

のすべてのオーバーロードでContinueWith()、最初のパラメーターは を受け取るデリゲートであるTaskため、パラメーターなしのデリゲートを渡すことはできません。

ラムダを使用することはまったく問題なく、読みやすさを損なうことはないと思います。また、コード内のラムダは不必要に冗長です。

Task.Factory.StartNew(MethodNoArguments).ContinueWith(_ => MethodNoArguments())

または、Cory Carson がコメントで指摘したように、拡張メソッドを記述できます。

public static Task ContinueWith(this Task task, Action action)
{
    return task.ContinueWith(_ => action());
}
于 2012-05-17T10:02:12.770 に答える
5

複数の継続を使用するときにきれいなコードを書くのはそれほど簡単ではありませんが、コードをきれいにするためのいくつかの規則に従うことができます。

  1. svick's answer の短い形式を使用してください
  2. 継続の連鎖は避けてください。各継続の結果を別の変数に格納し、別の行で ContinueWith を呼び出します
  3. 継続コードが長い場合は、それをラムダ変数に格納してから、ラムダで ContinueWith を実行します。
  4. この " Then "メソッドのような拡張メソッドを使用して、コードをさらにきれいにします。

コードを次のように変更すると、少しすっきりします。

        var call1=Task.Factory.StartNew(()=>MethodNoArguments());
        var call2 = call1.ContinueWith(_ => MethodNoArguments());
        call2.Wait();

あるいは

        var call1 = Task.Factory.StartNew<Task>(MethodNoArguments);
        var call2 = call1.Then(MethodNoArguments);
        call2.Wait();

Stephen Toub は、タスクを使用した非同期操作のシーケンスの処理で、Then 拡張機能とコードをクリーンアップするその他の方法について説明しています。

この問題は、C# 4 では完全に解決されています。C# 5 では、async/await キーワードを使用して、元の同期バージョンのように見えるクリーンなコードを作成できます。たとえば、次のようになります。

    static async Task Run()
    {
        await MethodNoArguments();
        await MethodNoArguments();
    }

    static async Task MethodNoArguments()
    {
        await Task.Run(()=>Console.WriteLine("MethodNoArguments()"));
    }

Visual Studio 11 と .NET 4.5 には Go Live ライセンスがあるため、おそらくすぐに使い始めることができます。

C# 4 で Async CTP を使用して、同じ結果を得ることができます。Go Live ライセンスがあるため、本番環境で Async CTP を使用できます。欠点は、CTP と .NET 4.5 の違いにより、.NET 4.5 に移行するときにコードに小さな変更を加える必要があることです (たとえば、CTP には Task.Run ではなく TaskEx.Run があります)。

于 2012-05-17T11:29:33.150 に答える