Adr*_*mas 13 .net c# asynchronous dry
我有一个像这样的方法:
public void Encrypt(IFile file)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
string tempFilename = GetFilename(file);
using (var stream = new FileStream(tempFilename, FileMode.OpenOrCreate))
{
this.EncryptToStream(file, stream);
file.Write(stream);
}
File.Delete(tempFilename);
}
Run Code Online (Sandbox Code Playgroud)
但是,我想要编写另一个非常相似的方法,但它会调用WriteAsync,例如:
public async Task EncryptAsync(IFile file)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
string tempFilename = GetFilename(file);
using (var stream = new FileStream(tempFilename, FileMode.OpenOrCreate))
{
this.EncryptToStream(file, stream);
await file.WriteAsync(stream);
}
File.Delete(tempFilename);
}
Run Code Online (Sandbox Code Playgroud)
但是,我不喜欢有两种方法实际上重复代码.我怎么能避免这个?正确的方法感觉我应该使用Action/Delegate,但签名是不同的....
思考?
Ste*_*ary 18
但是,我不喜欢有两种方法实际上重复代码.我怎么能避免这个?
有一些方法,如我的关于棕色异步开发的MSDN文章中所述.
1)使自然异步API仅异步.
这是最激烈的解决方案(在向后兼容性方面),但从技术角度来看,你可以说它是最正确的.使用这种方法,您将替换 Encrypt为EncryptAsync.
虽然这是IMO的最佳方法,但您的最终用户可能不同意.:)
2)应用hack在异步版本上阻塞.
public void Encrypt(IFile file)
{
EncryptAsync(file).GetAwaiter().GetResult();
}
Run Code Online (Sandbox Code Playgroud)
请注意(正如我在我的博客中所描述的),为避免死锁,您需要ConfigureAwait(false)在异步版本中的任何位置使用.
这个黑客的缺点:
ConfigureAwait(false)每一个await在你的async版本,每次调用方法.忘掉一个,你就有可能陷入僵局.请注意,某些库并不ConfigureAwait(false)适用于所有平台(特别是HttpClient在移动平台上).3)在线程池线程上应用运行异步版本的hack并阻塞它.
public void Encrypt(IFile file)
{
Task.Run(() => EncryptAsync(file)).GetAwaiter().GetResult();
}
Run Code Online (Sandbox Code Playgroud)
这种方法完全避免了死锁情况,但也有其自身的缺点:
4)传递一个标志参数.
如果你不愿采取方法(1),这是我最喜欢的方法.
private async Task EncryptAsync(IFile file, bool sync)
{
if (file == null)
throw new ArgumentNullException(nameof(file));
string tempFilename = GetFilename(file);
using (var stream = new FileStream(tempFilename, FileMode.OpenOrCreate))
{
this.EncryptToStream(file, stream);
if (sync)
file.Write(stream);
else
await file.WriteAsync(stream);
}
File.Delete(tempFilename);
}
public void Encrypt(IFile file)
{
EncryptAsync(file, sync: true).GetAwaiter().GetResult();
}
public Task EncryptAsync(IFile file)
{
return EncryptAsync(file, sync: false);
}
Run Code Online (Sandbox Code Playgroud)
布尔标志肯定是丑陋的 - 并且是正确的OOP设计的红色标志 - 但它隐藏在一个private方法中,而不像其他黑客那样危险.
我的文章中介绍了其他几个hacks(单线程线程池上下文和嵌套消息循环),但我通常不推荐它们.
另外,如果您的代码确实在使用FileStream,则需要显式打开它以进行异步访问以获得真正的异步操作.也就是说,您必须调用构造函数来传递参数,或者true在isAsync参数FileOptions.Asynchronous的值中设置标志options.