4

わかりました、悪いタイトルですが、私はより良い名前を思いつきませんでした..私の質問はおそらく async/await に固有のものでさえありませんが、私の質問は非同期処理中に出てくるので、そのようにポーズをとります. :

タスクのリストを作成してから「await Task.WhenAll(タスクのリスト)」を実行するメソッドがいくつかあります。これらのメソッドで待機している特定の種類のタスクはさまざまです。たとえば、一部のメソッドは のリストを待機していますがTask<String>、他の人は のリストを待っていますTask<foo>

私が見つけたのは、これらの各メソッドの Task.WhenAll() の周りで重要な try/catch 処理を行う必要があり、そのコードは常に同じであるということです。そのコードを共通メソッドに移動してから、タスクのリストを渡し、その共通メソッドの問題を発生させ、次に WhenAll を try/finally にまとめたいと考えています。

しかし、私が直面している問題は、このメソッドを呼び出す各メソッドが異なる Task タイプのリストを渡すことです。これにより、共通メソッドのパラメーターをただの Task として宣言すると、コンパイラが文句を言います。

methodA:
    List<Task<String>> myTaskList = ...
    ExecuteTasks(myTaskList);

methodB:
    List<Task<Foo>> myTaskList = ...
    ExecuteTasks(myTaskList);

 async Task ExecuteTasks(List<Task> taskList) {
    try {
        await Task.WhenAll(taskList)
        }
    catch {
        ..common catch handling goes here. This handling isn't really sensitive to the
        ..type of the Tasks, we just need to examine it's Status and Exception properties..
        }
    }

上記では、methodA と methodB にはそれぞれ、ExecuteTasks に渡す必要がある独自の種類のタスク リストがありますが、問題は、コンパイラが型の不一致について文句を言わないように、タスクのリストを ExecuteTasks に定義する方法です。非ジェネリックの世界では、コンパイラがそれらを「アップキャスト」できるように、メソッド A とメソッド B のリストの型のスーパークラスである ExecuteTasks にパラメーターを定義する可能性がありますが、このアプローチはここでは機能しないようです.. (私は ExecuteTasks を取るように定義しようとしましたTask<Object>が、それはタイプの不一致の問題を解決しませんでした)

4

3 に答える 3

2

代わりにあなたExecuteTasksを入力してみてください:IEnumerable<Task>

async Task ExecuteTasks(IEnumerable<Task> taskList) {

@Hamish Smith が指摘したように、これは共分散の問題です。

List<Task<String>> myTaskList = ...

ExecuteTasks(myTaskList);

async Task ExecuteTasks(IEnumerable<Task> taskList) {
    try {
        await Task.WhenAll(taskList)
        }
    catch {
        //..common catch handling goes here. This handling isn't really sensitive to the
        //..type of the Tasks, we just need to examine it's Status and Exception properties..
        }
}

それがまだタイプされている場合はList<Task>、次のようなばかげたことを行うことができます。

List<Task<String>> myTaskList = ...

ExecuteTasks(myTaskList);

async Task ExecuteTasks(List<Task> taskList) {
        taskList.Add(new Task<int>()) // bad stuff
}
于 2012-11-13T21:29:17.863 に答える
1
var intTask1 = Task.Run(() => 1);
var intTask2 = Task.Run(() => 2);
var intTasks = new List<Task<int>> { intTask1, intTask2 };

var intExecutor = new TaskExecutor<int>();
await intExecutor.ExecuteTasks(intTasks);

var stringTask1 = Task.Run(() => "foo");
var stringTask2 = Task.Run(() => "bar");
var stringTasks = new List<Task<string>> { stringTask1, stringTask2 };

var stringExecutor = new TaskExecutor<string>();
await stringExecutor.ExecuteTasks(stringTasks);

...................................................

class TaskExecutor<T>
{
    public async Task ExecuteTasks(IEnumerable<Task<T>> tasks)
    {
        try
        {
            await Task.WhenAll(tasks);
        }
        catch (Exception ex)
        {
            // Handle exception
        }
    }
}
于 2012-11-13T21:34:25.747 に答える
0

反分散と共分散に関する Eric Lippert のシリーズと、ジェネリックがコンパイラによってどのように認識されるか (http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance- and-contravariance-in-c-part-one.aspx)...
ここでジェネリックメソッドが機能するかどうか疑問に思いますか?

  async Task ExecuteTasks<T>(List<Task<T>> taskList) 
  {
     try 
     {
        await Task.WhenAll(taskList);
     }
     catch 
     {
        //..common catch handling goes here. This handling isn't really sensitive to the
        //..type of the Tasks, we just need to examine it's Status and Exception properties..
     }
  }
于 2012-11-13T21:17:09.520 に答える