英文:
Correct way of using Func<Task<T>>
问题
第一个代码段:
static void Main(string[] args)
{
Func<Task<int>> getter = async () => await Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
await Task.Delay(1000);
return 1;
}
第二个代码段:
static void Main(string[] args)
{
Func<Task<int>> getter = () => Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
await Task.Delay(1000);
return 1;
}
请注意,这两个代码段的主要区别在于第一个代码段中,getter
是一个异步 lambda 表达式,其中使用了 await
来等待 Get()
方法的完成。而在第二个代码段中,getter
直接指向了 Get()
方法,没有使用异步关键字。
英文:
I have two code section in both of them I'm trying to use Func<Task<T>>. Can anyone point out the difference between below two code sections. Which approach should I follow.
static void Main(string[] args)
{
Func<Task<int>> getter = async () => await Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
await Task.Delay(1000);
return 1;
}
static void Main(string[] args)
{
Func<Task<int>> getter = () => Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
await Task.Delay(1000);
return 1;
}
答案1
得分: 2
这是您提供的代码的翻译:
不同之处在于错误时的堆栈跟踪。如果您稍微修改代码如下,您会看到结果的差异。
内部类 Example1
{
public static void Main(string[] args)
{
Func<Task<int>> getter = async () => await Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
throw new Exception("test");
await Task.Delay(1000);
return 1;
}
}
内部类 Example2
{
public static void Main(string[] args)
{
Func<Task<int>> getter = () => Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
throw new Exception("test");
await Task.Delay(1000);
return 1;
}
}
当 Example1 抛出异常时,你会看到以下堆栈跟踪。通过查看堆栈跟踪,你知道 Get() 方法是从匿名方法中调用的。
此异常最初是在此调用堆栈上引发的:
StackOverflow.CSharp.Example1.Get() 在 Example.cs 中
StackOverflow.CSharp.Example1.Main.AnonymousMethod__0_0() 在 Example.cs 中
然而,当 Example2 抛出异常时,堆栈跟踪被减少,不显示 Get() 被调用的位置。追踪潜在问题可能会很困难。
此异常最初是在此调用堆栈上引发的:
StackOverflow.CSharp.Example2.Get() 在 Example.cs 中
在我们的项目中,我们更喜欢使用带有 async/await 的第一种方法。
英文:
The difference is a stacktrace in case of errors. If you modify the code a bit as following, you would see how results differ.
internal class Example1
{
public static void Main(string[] args)
{
Func<Task<int>> getter = async () => await Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
throw new Exception("test");
await Task.Delay(1000);
return 1;
}
}
internal class Example2
{
public static void Main(string[] args)
{
Func<Task<int>> getter = () => Get();
int x = getter().Result;
Console.WriteLine("hello : " + x);
}
static async Task<int> Get()
{
throw new Exception("test");
await Task.Delay(1000);
return 1;
}
}
When Example1 throws the exception, you see a stacktrace as following. Looking at the stacktrace, you know that the Get() method was called from the anonymous method.
This exception was originally thrown at this call stack:
StackOverflow.CSharp.Example1.Get() in Example.cs
StackOverflow.CSharp.Example1.Main.AnonymousMethod__0_0() in Example.cs
However, when Example2 throws the exception, the stacktrace is reduced and does not show where Get() was called from. It could be hard to trace a potential problem.
This exception was originally thrown at this call stack:
StackOverflow.CSharp.Example2.Get() in Example.cs
In our projects, we prefer the first approach with async/await.
答案2
得分: 0
以下是翻译好的内容:
对于像这样的简单情况,两个示例基本上会做相同的事情。
作为一个经验法则,您应该在可以的地方直接返回任务,而不是等待。也就是说,在您调用返回任务的单个方法而不对结果进行任何处理的情况下。但这主要是出于代码风格的原因,即避免可能会使读者困惑的不必要关键字。因此,示例2将被优先选择。
当然,在您特定的示例中,您可能根本不应该使用异步,而是更倾向于使用 Thread.Sleep
。在UI程序中,您应避免使用 .Result
,因为它会阻塞UI线程,并增加了死锁的风险。
英文:
For a trivial case like this both examples will do more or less the same thing.
As a rule of thumb you should return the task directly without awaiting where you can. I.e. in cases where you call a single method that returns a task and do not do any processing of the result. But this is mostly for code style reasons, i.e. avoiding unnecessary keywords that might confuse a reader. So example 2 would be preferred.
Ofc. In your specific example you should probably not use async at all, and prefer Thread.Sleep
. In a UI program you should avoid using .Result
, since it will block the UI thread, and increases the risk of deadlocks.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论