C# 重构2个接收回调函数的相同函数<;任务<;T>&燃气轮机;和Func<;T>;分别地 公共静态异步任务NDC(Func Func) { 使用(SomeDisposable()) { 尝试 { return wait func(); } 捕获(例外情况除外) { 控制台写入线(“错误”); 投掷; } } } 公共静态T NDC(Func Func) { 使用(SomeDisposable()) { 尝试 { 返回func(); } 捕获(例外情况除外) { 控制台写入线(“错误”); 投掷; } } }
如您所见,这两个函数几乎相同。它们之间唯一的区别是,当回调是C# 重构2个接收回调函数的相同函数<;任务<;T>&燃气轮机;和Func<;T>;分别地 公共静态异步任务NDC(Func Func) { 使用(SomeDisposable()) { 尝试 { return wait func(); } 捕获(例外情况除外) { 控制台写入线(“错误”); 投掷; } } } 公共静态T NDC(Func Func) { 使用(SomeDisposable()) { 尝试 { 返回func(); } 捕获(例外情况除外) { 控制台写入线(“错误”); 投掷; } } },c#,multithreading,generics,async-await,task,C#,Multithreading,Generics,Async Await,Task,如您所见,这两个函数几乎相同。它们之间唯一的区别是,当回调是Func时,它将被等待,因此返回类型是Task,否则,函数将返回类型T 我想对这些函数进行分组/泛型,有什么方法可以实现吗?提前谢谢 注意:如果调用方调用了非任务版本,则此函数中的所有进程都应在单个线程中运行。您可以从异步版本派生同步版本,如下所示: public static async Task<T> NDC<T>(Func<Task<T>> func) { using (So
Func
时,它将被等待,因此返回类型是Task
,否则,函数将返回类型T
我想对这些函数进行分组/泛型,有什么方法可以实现吗?提前谢谢
注意:如果调用方调用了非任务版本,则此函数中的所有进程都应在单个线程中运行。您可以从异步版本派生同步版本,如下所示:
public static async Task<T> NDC<T>(Func<Task<T>> func)
{
using (SomeDisposable())
{
try
{
return await func();
}
catch (Exception ex)
{
Console.WriteLine("error");
throw;
}
}
}
public static T NDC<T>(Func<T> func)
{
using (SomeDisposable())
{
try
{
return func();
}
catch (Exception ex)
{
Console.WriteLine("error");
throw;
}
}
}
publicstatictdc(Func-Func)
{
如果(func==null)抛出新的ArgumentNullException(nameof(func));
返回NDC(()=>Task.FromResult(func()).GetAwaiter().GetResult();
}
有两个陷阱:
NDC
方法中验证func
参数。除非使用可为空的引用类型,如注释中的Alexei Levenkov
等待func()时有效
是异步NDC
方法中唯一等待的操作。否则,当前线程将被阻塞,坏事情将发生(可伸缩性降低或死锁,取决于应用程序的类型)
您可以从异步版本派生同步版本,如下所示:
public static async Task<T> NDC<T>(Func<Task<T>> func)
{
using (SomeDisposable())
{
try
{
return await func();
}
catch (Exception ex)
{
Console.WriteLine("error");
throw;
}
}
}
public static T NDC<T>(Func<T> func)
{
using (SomeDisposable())
{
try
{
return func();
}
catch (Exception ex)
{
Console.WriteLine("error");
throw;
}
}
}
publicstatictdc(Func-Func)
{
如果(func==null)抛出新的ArgumentNullException(nameof(func));
返回NDC(()=>Task.FromResult(func()).GetAwaiter().GetResult();
}
有两个陷阱:
NDC
方法中验证func
参数。除非使用可为空的引用类型,如注释中的Alexei Levenkov
等待func()时有效
是异步NDC
方法中唯一等待的操作。否则,当前线程将被阻塞,坏事情将发生(可伸缩性降低或死锁,取决于应用程序的类型)
库作者提供方法的同步和异步变体是有原因的……它们被设计为以不同的方式调用,并具有不同的语义。这是一个糟糕的使用,最终会导致难以维护的代码。即使在using语句中包装disposables也可能不会使用相同的实现。让我删除它。这是库作者提供同步和异步方法变体的原因……它们被设计为以不同的方式调用,并具有不同的语义。这是一个不好用的干,最终会导致难以维护的代码。此外,考虑到引入<代码> IASYNCUnaby,即使在使用语句中包装处理也可能不使用相同的实现。我仍然会进入多线程环境,这是我想要的avoid@mannok我不知道并发是如何发生的,除非
NDC
方法中还有其他等待的操作,您还没有向我们展示。很好的一点是,您可以通过知道async one不会使用同步回调实际运行async来实际升级同步版本。。。两个注意事项:对于C#9,您有可为空的引用类型,它允许您跳过空检查。。。实际上,由于在这种情况下没有异步执行,您可以只执行.Result
。。。(如果NDC
除了有实际的异步调用之外,没有很好的理由尝试将它们结合起来)@AlexeiLevenkov我不太喜欢可空引用的概念。我看到这些卷曲的问号像语言污染一样随处可见。:-)关于使用.Result
属性,这是否会在AggregateException
中包装一个可能的异常?似乎如果我这样做,我仍然会进入我想要的多线程环境avoid@mannok我看不出并发是如何发生的,除非在NDC
方法中还有其他等待的操作,您还没有向我们展示。很好的一点是,您可以通过知道async one不会实际使用同步回调运行async来升级同步版本。。。两个注意事项:对于C#9,您有可为空的引用类型,它允许您跳过空检查。。。实际上,由于在这种情况下没有异步执行,您可以只执行.Result
。。。(如果NDC
除了有实际的异步调用之外,没有很好的理由尝试将它们结合起来)@AlexeiLevenkov我不太喜欢可空引用的概念。我看到这些卷曲的问号像语言污染一样随处可见。:-)关于使用.Result
属性,这是否会在聚合异常
中包装一个可能的异常?