好吧,糟糕的标题,但我想不出一个更好的名字。我的问题甚至可能不是特定于async / await,但我的问题是在异步处理期间出现,所以我要打扮那样:
我有几种方法可以创建任务列表,然后执行'await Task.WhenAll(任务列表)'。这些方法中正在等待的特定类型的任务有所不同。例如,某些方法正在等待列表Task<String>
的{{1}},而其他人正在等待Task<foo>
的列表。
我发现我需要在每个方法中围绕Task.WhenAll()进行一些非平凡的try / catch处理,并且代码总是相同的。我想将该代码移动到一个通用的方法,然后传入任务列表,并将那个常见的方法问题发送到WhenAll,包含在try / finally中。
但我遇到的问题是,调用此方法的每个方法都将传递不同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的任务列表,以便编译器不会抱怨类型不匹配?在非通用的世界中,我可能会将参数定义为ExecuteTasks,它是methodA和methodB列表类型的超类,因此编译器可以“向上”它们,但这种方法似乎在这里不起作用.. (我尝试将ExecuteTasks定义为采用Task<Object>
,但这并未解决类型不匹配问题)
答案 0 :(得分: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
}
答案 1 :(得分: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
}
}
}
答案 2 :(得分: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..
}
}