C# 如何实现异步方法和同步方法?
我有一个方法,比如C# 如何实现异步方法和同步方法?,c#,.net,task-parallel-library,C#,.net,Task Parallel Library,我有一个方法,比如Task-GetContentAsync(stringurl),我的控制台应用程序还没有准备好在内部利用TPL,但可能以后会这样做 如何轻松地为此(或其他)方法编写同步包装器(不是替代实现)?下面是一个测试用例的代码,它表明可以以非常简单的方式完成此操作。为了演示,我还实现了一个GetContentAsync方法 using System.IO; using System.Net; using System.Threading.Tasks; namespace AsyncTe
Task-GetContentAsync(stringurl)
,我的控制台应用程序还没有准备好在内部利用TPL,但可能以后会这样做
如何轻松地为此(或其他)方法编写同步包装器(不是替代实现)?下面是一个测试用例的代码,它表明可以以非常简单的方式完成此操作。为了演示,我还实现了一个
GetContentAsync
方法
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace AsyncTestCase.Driver
{
public class AsyncTestCase
{
public AsyncTestCase()
{ }
public string GetContent(string url)
{
Task<string> task = this.GetContentAsync(url);
return task.Result;
}
public async Task<string> GetContentAsync(string url)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse;
using (Stream stream = response.GetResponseStream())
{
using (TextReader reader = new StreamReader(stream))
{
string content = await reader.ReadToEndAsync();
return content;
}
}
}
}
}
如果库需要同时实现同步和异步成员,那么就同时实现这两个成员。没有快捷方式(假设这是一个可重用的库) 公共异步任务GetContentAsync(字符串url) { …//此处的逻辑,例如,使用HttpClient } 公共字符串GetContent(字符串url) { …//此处重复逻辑,例如,使用WebClient } 逻辑的重复当然是不幸的,但如果你试图走捷径,你最终会陷入更糟糕的境地。关于“为什么”的细节对于一个如此的答案来说有点长,但是Stephen Toub在他的经典博客文章和
顺便说一句,这两个问题的答案都是“不”。另外,请参见。这通常是一个非常糟糕的主意。关于为什么会这样的详细解释,请向任何投反对票的人咨询。你能提供关于这个答案如何“没有用处”的信息吗?目前有一篇关于这个答案的评论,解释了为什么这个答案不好,并链接到一篇文章,该文章深入解释了使用这个答案可能导致的非常严重的问题。该评论也有三张赞成票,表明其他一些读者认为它特别相关。那条评论在你发表评论前一个多小时就已经发布了,所以我认为现在你已经有足够的机会看到它了。答案是不正确的,没有你预期的功能,虽然它可能对一些人有用,建议使用它是非常有害的,因为很大比例的用户在使用它时会导致严重的问题(即,使整个程序死锁)。我已经将您链接到多个资源,描述代码死锁的原因;信息太多,无法在评论中充分描述;我试图这样做,但很明显,总结对你来说是不够的。与其让我深入探讨,不如让你读一读这篇文章,确切地解释为什么这不好。但是,你能证明吗?你基本上是在要求我们把你的话当作福音,不断地提出一些无关的事情。这不是针对任何类型的UI应用程序,而是针对没有同步上下文行为的基本控制台应用程序。你现在竟然否决了我关于这个话题的所有答案,并且否决了那些你根本不同意的有用答案的人。这是对投票系统的滥用,因为答案在问题的上下文中是有用的。@Servy这与UI响应无关,因此不是该问题的重复。@MichaelJ.Gray确实不是完全重复的,但是该问题的答案回答了这个问题,这使它成为了关闭功能的适当使用。@Servy考虑到您需要在该答案中实现一些消息泵送系统,这在控制台应用程序中基本上没有任何用处,我认为它使用过度设计的解决方案不恰当地解决了这一问题。通过访问
Task.Result
@MichaelJ.Gray 1)这是一个非常有用的工具,即使在控制台应用程序中,在控制台应用程序中也不会出现持续死锁问题。事实上,如果您阅读了那篇文章中链接的文章,那么创建它的全部原因就是在控制台应用程序中创建同步上下文的一种方法。接下来,虽然控制台应用程序在默认情况下没有同步上下文,因此不会死锁,但您可以在控制台应用程序中创建一个同步上下文,这可能会使代码死锁,所以控制台应用程序不能完全忽略这个问题。@Servy,除了我设置了上下文的部分,它仍然可以正常工作。我读了你的答案,它们看起来不错,但我想为另一个方法编写一个包装,没有第二个实现使用同步方法调用,一个是HttpClient
,另一个是WebClient
。我想这有点模棱两可,人们可能不会把“包装器”理解为明确的包装器,它可能会根据人们的思维过程提出“替代实现”。@MichaelJ.Gray:我知道你想要一个简单的包装器。我的观点是你不能拥有它我不想要简单的包装,我想要一个包装期。我不想要替代的实现。这就是问题的本质。通过使用代码生成,几乎可以为每种情况(即使是非异步上下文)生成通用解决方案。尽管这比为一个方法制作一个包装器或组合一个可以用来制作包装器的模式要复杂得多。但是我要说的是,如果你的答案不是严格地与制作包装器有关,而只是着眼于启动并运行异步功能,那么你的答案将满足这个问题。@MichaelJ.Gray:我认为代码生成是一种很好的未来方法。我现在不会说这是可行的,即使是对于一个大型的代码库,但也许在Roslyn的几个版本之后(目前还有一个版本仍在保密协议下)。也就是说,我不认为代码生成是一个“包装器”。很好的发现。
namespace AsyncTestCase.Driver
{
internal static class Program
{
private static void Main()
{
AsyncTestCase test = new AsyncTestCase();
string content = test.GetContent("http://www.google.com");
}
}
}
public async Task<string> GetContentAsync(string url)
{
... // Logic here, e.g., using HttpClient
}
public string GetContent(string url)
{
... // Duplicate logic here, e.g., using WebClient
}