4

好吧,标题不好,但我想不出更好的名字。我的问题可能甚至不是特定于异步/等待的,但我的问题是在异步处理期间出现的,所以我打算这样提出:

我有几种方法可以创建任务列表,然后执行“await Task.WhenAll(任务列表)”。在这些方法中等待的具体任务类型各不相同。例如,一些方法正在等待列表Task<String>,而其他人正在等待Task<foo>.

我发现我需要在这些方法中的每一个中围绕 Task.WhenAll() 进行一些重要的尝试/捕获处理,并且该代码始终相同。我想将该代码移到一个通用方法中,然后传入任务列表,然后将该通用方法问题处理好,然后将其包含在 try/finally 中。

但是我遇到的问题是调用此方法的每个方法都将传入不同任务类型的列表,当我将公共方法的参数声明为任务时,这会导致编译器抱怨:

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,这样编译器才不会报类型不匹配?在非泛型世界中,我可能会将 ExecuteTasks 的参数定义为 methodA 和 methodB 列表类型的超类,以便编译器可以“向上转换”它们,但这种方法似乎在这里不起作用.. (我尝试将 ExecuteTasks 定义为采用 aTask<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 回答