C#泛型和void的特殊情况

时间:2014-01-21 17:11:55

标签: c# generics async-await

我编写了一个函数,它将使用相对较新的async / await模式在线程上运行任何函数,并稍后通过可选的回调方法通知调用者。该功能非常简单,如下所示:

private async void DoOperationAsync<T>(Func<T> operation, Action<T> resultAction = null)
{
    if (operation == null)
        throw new ArgumentNullException("operation");

    var result = await Task<T>.Factory.StartNew(operation);

    // Notify someone that this finished
    if (resultAction != null)
        resultAction(result);
}

这对于返回值的函数非常有效。它不适用于返回void的函数(或者我可能不够聪明,无法使其工作)。我可以编写一个不承担返回类型的特殊情况。但是,我想知道一些C#泛型专家是否可以在这种情况下指出一种处理void的方法。是否有工作方式不涉及无效功能的特殊情况?

4 个答案:

答案 0 :(得分:5)

我的博客上有async/await intro,您可能会觉得有帮助。

  

我编写了一个函数,使用相对较新的async / await模式运行线程上的任何函数,稍后通过可选的回调方法通知调用者。

这就是Task.Run的用途。

  

我确实希望该方法在调用线程上运行(在我的例子中,它通常是我的应用程序的主要UI线程)。

await已经做到了。

所以,不要像这样编写代码:

DoOperationAsync(() =>
{
  // Code that runs on threadpool thread.
  return 13;
},
result =>
{
  // Code that runs on UI thread.
  MessageBox.Show(result.ToString());
});

这样做:

var result = await Task.Run(() =>
{
  // Code that runs on threadpool thread.
  return 13;
});
// Code that runs on UI thread.
MessageBox.Show(result.ToString());

P.S。 Task.Run已经具有处理带有和不带返回值的委托的所有必要重载。

答案 1 :(得分:1)

对于无效的async方法,请使用Task

的类型

答案 2 :(得分:0)

尝试使用非通用版本的方法,在执行回调之前等待非通用任务

private async void DoOperationAsync(Func operation, Action resultAction = null)
{
    if (operation == null)
        throw new ArgumentNullException("operation");

    await Task.Factory.StartNew(operation);

    // Notify someone that this finished
    if (resultAction != null)
        resultAction();
}

答案 3 :(得分:0)

你应该避免包裹Task<T>.Factory.StartNew。请直接使用它,并在可能的情况下尽量使用Task.Run,在答案中为@StephenCleary advises

尽管如此,我认为你的问题仍然适用于其他一些模式。如果您不想实现该方法的泛型和非泛型版本,则可以使用伪Empty结构作为泛型参数。例如,TPL中有TaskCompletionSource<T>类和Task.FromResult<T>方法类型,它们没有非泛型版本。如果您不想泄露信息,代码可能类似于:

public struct Empty {
    public static Empty Value {
        get { return default(Empty); }
}

static Task GetCompletedTask() { 
    return Task.FromResult(Empty.Value); } 

您可以将任何void方法转换为Empty func:

static Func<Empty> Func(Action action) {
    return () => { action(); return Empty.Value; };
}

DoOperationAsync(Func(() =>
    Console.WriteLine("Hello, World!")));

这可以使它与现有的泛型方法一起使用,而不会将任何结果泄露给调用者。