是否可以在 C# 5.0 中使用相同的异步方法签名,并能够在以后决定如何执行此类方法

本文关键字:决定 何执行 类方法 执行 异步方法 是否 | 更新日期: 2023-09-27 18:34:05

我想使用最近的 C# 5.0 异步方法,但有一些特定的方式。

请考虑以下示例代码:

public abstract class SomeBaseProvider : ISomeProvider
{
   public abstract Task<string> Process(SomeParameters parameters);    
}
public class SomeConcreteProvider1 : SomeBaseProvider 
{
   // in this method I want to minimize any overhead to create / run Task
   // NOTE: I remove here async from method signature, because basically I want to run 
   // method to run in sync!
   public override Task<string> Process(SomeParameters parameters) {
      string result = "string which I don't need any async code to get";
      return Task.Run(() => result);
   }
}
public class SomeConcreteProvider2 : SomeBaseProvider 
{
   // in this method, it's OK for me to use async / await 
   public async override Task<string> Process(SomeParameters parameters) {
      var data = await new WebClient().DownloadDataTaskAsync(urlToRequest);
      string result = // ... here we convert data byte[] to string some way
      return result;
   }
}

现在我将如何使用异步方法(您可以忽略消费者实际上 ASP.NET MVC4 应用程序的事实......它可以是任何东西(:

public class SomeAsyncController : AsyncController
{
    public async Task<ActionResult> SomethingAsync(string providerId)
    {
       // we just get here one of providers I define above
       var provider = SomeService.GetProvider(providerId);
       // we try to execute here Process method in async. 
       // However we might want to actually do it in sync instead, if  
       // provider is actually SomeConcreteProvider1 object.
       string result = await provider.Process(new SomeParameters(...));
       return Content(result);
     }
} 

如您所见,我有 2 个实现,每个实现都会以不同的方式执行:一个我想异步运行并且不阻塞线程 (SomeConcreteProvider2(,而另一个我希望能够同步运行并且不创建任何 Task 对象等(我无法在上面的代码中编码,即我确实在这里创建新任务!

已经有问题了,例如我将如何同步运行异步任务方法?。但是我不想同步运行某些东西...如果我在代码时(即在运行时之前(知道某些方法实现实际上不是异步的,并且不需要使用任何线程/I/O 完成端口等,我想避免任何开销。如果你检查上面的代码,很容易看出SomeConcreteProvider1中的方法基本上会构造一些字符串(html(,可以在同一执行线程上非常快速地完成。但是,SomeConcreteProvider2 中的相同方法将需要创建 Web 请求、获取 Web 响应并以某种方式处理它,我确实希望至少异步发出 Web 请求,以避免在请求期间阻塞整个线程(实际上可能会退出很长时间(。

所以问题是:如何组织我的代码(不同的方法签名或不同的实现,或者?(以便能够决定如何执行方法并避免任何可能的开销,例如由SomeConcreteProvider1.Process方法中的Task.Run(...(引起的?

更新1:明显的解决方案(我在问题过程中想到了其中一些(,例如向每个提供程序添加一些静态属性(例如"isAsyncImplementation"(,然后检查该属性以决定如何运行方法(在控制器操作中使用await或不使用await(也有一些开销:D如果可能的话,我想要更好的东西:D

是否可以在 C# 5.0 中使用相同的异步方法签名,并能够在以后决定如何执行此类方法

在第一种情况下,我建议返回:

Task.FromResult(result)

返回一个现成的任务。

http://msdn.microsoft.com/en-us/library/hh194922%28v=vs.110%29.aspx

你的设计看起来不错。

对于SomeConcreteProvider1情况,您可以使用 TaskCompletionSource

这将返回一个Task,而不需要并发。

此外,在使用者代码中,如果Task已经完成,await将不会产生。这称为"快速路径",并有效地使方法同步。