C# 警告不等待此调用,继续执行当前方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14903887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
warning this call is not awaited, execution of the current method continues
提问by Mud
Just got VS2012 and trying to get a handle on async
.
刚刚获得 VS2012 并试图处理async
.
Let's say I've got an method that fetches some value from a blocking source. I don't want caller of the method to block. I could write the method to take a callback which is invoked when the value arrives, but since I'm using C# 5, I decide to make the method async so callers don't have to deal with callbacks:
假设我有一个方法可以从阻塞源获取一些值。我不希望该方法的调用者被阻止。我可以编写方法来获取值到达时调用的回调,但由于我使用的是 C# 5,我决定使方法异步,因此调用者不必处理回调:
// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
return Task.Factory.StartNew(() => {
Console.Write(prompt);
return Console.ReadLine();
});
}
Here's an example method that calls it. If PromptForStringAsync
wasn't async, this method would require nesting a callback within a callback. With async, I get to write my method in this very natural way:
这是调用它的示例方法。如果PromptForStringAsync
不是异步的,则此方法需要在回调中嵌套回调。使用异步,我可以用这种非常自然的方式编写我的方法:
public static async Task GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
Console.WriteLine("Welcome {0}.", firstname);
string lastname = await PromptForStringAsync("Enter your last name: ");
Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}
So far so good. The problem is when I callGetNameAsync:
到现在为止还挺好。问题是当我调用GetNameAsync 时:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
The whole point of GetNameAsync
is that it's asynchronous. I don't wantit to block, because I want to get back to the MainWorkOfApplicationIDontWantBlocked ASAP and let GetNameAsync do its thing in the background. However, calling it this way gives me a compiler warning on the GetNameAsync
line:
重点GetNameAsync
是它是异步的。我不希望它被阻塞,因为我想尽快回到 MainWorkOfApplicationIDontWantBlocked 并让 GetNameAsync 在后台做它的事情。但是,以这种方式调用它会给我一个编译器警告GetNameAsync
:
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
I'm perfectly aware that "execution of the current method continues before the call is completed". That's the pointof asynchronous code, right?
我非常清楚“在调用完成之前继续执行当前方法”。这是该点的异步代码,对不对?
I prefer my code to compile without warnings, but there's nothing to "fix" here because the code is doing exactly what I intend it to do. I can get rid of the warning by storing the return value of GetNameAsync
:
我更喜欢我的代码在没有警告的情况下编译,但这里没有什么可以“修复”,因为代码正在做我想要做的事情。我可以通过存储返回值来消除警告GetNameAsync
:
public static void DoStuff()
{
var result = GetNameAsync(); // supress warning
MainWorkOfApplicationIDontWantBlocked();
}
But now I have superfluous code. Visual Studio seems to understand that I was forced to write this unnecessary code, because it suppresses the normal "value never used" warning.
但现在我有多余的代码。Visual Studio 似乎明白我被迫编写了这个不必要的代码,因为它抑制了正常的“从未使用过的值”警告。
I can also get rid of the warning by wrapping GetNameAsync in a method that's not async:
我还可以通过将 GetNameAsync 包装在非异步方法中来消除警告:
public static Task GetNameWrapper()
{
return GetNameAsync();
}
But that's even moresuperfluous code. So I have to write code I don't need or tolerate an unnecessary warning.
但那更是多余的代码。所以我必须编写我不需要的代码或容忍不必要的警告。
Is there something about my use of async that's wrong here?
我在这里使用 async 有什么问题吗?
采纳答案by Nikolay Khil
If you really don't need the result, you can simply change the GetNameAsync
's signature to return void
:
如果你真的不需要结果,你可以简单地将GetNameAsync
的签名更改为 return void
:
public static async void GetNameAsync()
{
...
}
Consider to see answer to a related question: What's the difference between returning void and returning a Task?
考虑查看相关问题的答案: 返回 void 和返回 Task 之间有什么区别?
Update
更新
If you need the result, you can change the GetNameAsync
to return, say, Task<string>
:
如果您需要结果,您可以更改GetNameAsync
返回值,例如Task<string>
:
public static async Task<string> GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
string lastname = await PromptForStringAsync("Enter your last name: ");
return firstname + lastname;
}
And use it as follows:
并按如下方式使用它:
public static void DoStuff()
{
Task<string> task = GetNameAsync();
// Set up a continuation BEFORE MainWorkOfApplicationIDontWantBlocked
Task anotherTask = task.ContinueWith(r => {
Console.WriteLine(r.Result);
});
MainWorkOfApplicationIDontWantBlocked();
// OR wait for the result AFTER
string result = task.Result;
}
回答by Guffa
It's your simplified example that causes the superflous code. Normally you would want to use the data that was fetched from the blocking source at some point in the program, so you would want the result back so that it would be possible to get to the data.
这是导致多余代码的简化示例。通常,您希望在程序中的某个时刻使用从阻塞源获取的数据,因此您希望返回结果,以便可以访问数据。
If you really have something that happens totally isolated from the rest of the program, async would not be the right approach. Just start a new thread for that task.
如果您真的有一些事情与程序的其余部分完全隔离,那么异步将不是正确的方法。只需为该任务启动一个新线程。
回答by devlord
According to the Microsoft article on this warning, you can solve it by simply assigning the returned task to a variable. Below is a translation of the code provided in the Microsoft example:
根据微软关于这个警告的文章,你可以通过简单地将返回的任务分配给一个变量来解决它。以下是 Microsoft 示例中提供的代码的翻译:
// To suppress the warning without awaiting, you can assign the
// returned task to a variable. The assignment doesn't change how
// the program runs. However, the recommended practice is always to
// await a call to an async method.
// Replace Call #1 with the following line.
Task delayTask = CalledMethodAsync(delay);
Note that doing this will result in the "Local variable is never used" message in ReSharper.
请注意,这样做将导致 ReSharper 中出现“从不使用局部变量”消息。
回答by Jonathan Allen
This is what I'm currently doing:
这就是我目前正在做的事情:
SomeAyncFunction().RunConcurrently();
Where RunConcurrently
is defined as...
其中RunConcurrently
定义为...
/// <summary>
/// Runs the Task in a concurrent thread without waiting for it to complete. This will start the task if it is not already running.
/// </summary>
/// <param name="task">The task to run.</param>
/// <remarks>This is usually used to avoid warning messages about not waiting for the task to complete.</remarks>
public static void RunConcurrently(this Task task)
{
if (task == null)
throw new ArgumentNullException("task", "task is null.");
if (task.Status == TaskStatus.Created)
task.Start();
}
回答by MrEs
async void
IS BAD!
async void
不好!
- What's the difference between returning void and returning a Task?
- https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html
- 返回 void 和返回 Task 有什么区别?
- https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html
What I suggest is that you explicitly run the Task
via an anonymous method...
我建议您Task
通过匿名方法显式运行...
e.g.
例如
public static void DoStuff()
{
Task.Run(async () => GetNameAsync());
MainWorkOfApplicationIDontWantBlocked();
}
Or if you did want it to block you can await on the anonymous method
或者,如果您确实希望它阻止您可以等待匿名方法
public static void DoStuff()
{
Task.Run(async () => await GetNameAsync());
MainWorkOfApplicationThatWillBeBlocked();
}
However, if your GetNameAsync
method has to interact with UI or even anything UI bound, (WINRT/MVVM, I'm looking at you), then it gets a little funkier =)
但是,如果您的GetNameAsync
方法必须与 UI 或什至任何 UI 绑定(WINRT/MVVM,我在看着您)进行交互,那么它会变得有点时髦 =)
You'll need to pass the reference to the UI dispatcher like this...
您需要像这样将引用传递给 UI 调度程序...
Task.Run(async () => await GetNameAsync(CoreApplication.MainView.CoreWindow.Dispatcher));
And then in your async method you'll need to interact with your UI or UI bound elements thought that dispatcher...
然后在你的异步方法中,你需要与你的 UI 或 UI 绑定元素进行交互,认为调度程序......
dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.UserName = userName; });
回答by Willem
I'm quite late to this discussion, but there is also the option to use the #pragma
pre-processor directive. I have some async code here and there that I explicitly do not want to await in some conditions, and I dislike warnings and unused variables just like the rest of you:
我对这个讨论已经很晚了,但也有使用#pragma
预处理器指令的选项。我在这里和那里有一些异步代码,我明确不想在某些情况下等待,并且我不喜欢警告和未使用的变量,就像你们其他人一样:
#pragma warning disable 4014
SomeMethodAsync();
#pragma warning restore 4014
The "4014"
comes from this MSDN page: Compiler Warning (level 1) CS4014.
该"4014"
来源于此MSDN页:编译器警告(等级1)CS4014。
See also the warning/answer by @ryan-horath here https://stackoverflow.com/a/12145047/928483.
另请参阅 @ryan-horath 此处https://stackoverflow.com/a/12145047/928483的警告/答案。
Exceptions thrown during an async call that is not awaited will be lost. To get rid of this warning, you should assign the Task return value of the async call to a variable. This ensures you have access to any exceptions thrown, which will be indicated in the return value.
在未等待的异步调用期间抛出的异常将丢失。要消除此警告,您应该将异步调用的 Task 返回值分配给一个变量。这确保您可以访问抛出的任何异常,这些异常将在返回值中指示。
Update for C# 7.0
C# 7.0 更新
C# 7.0 adds a new feature, discard variables: Discards - C# Guide, which can also help in this regard.
C# 7.0 添加了一个新功能,丢弃变量:丢弃 - C# 指南,它也可以在这方面提供帮助。
_ = SomeMethodAsync();
回答by Joe Savage
I'm not particularly fond of the solutions that either assign the task to an unused variable, or changing the method signature to return void. The former creates superfluous, non-intuitive code, while the latter may not be possible if you're implementing an interface or have another usage of the function where you want to use the returned Task.
我不是特别喜欢将任务分配给未使用的变量或更改方法签名以返回 void 的解决方案。前者创建了多余的、不直观的代码,而后者可能无法实现,如果您正在实现一个接口或在您想要使用返回的 Task 的地方使用该函数的其他用途。
My solution is to create an extension method of Task, called DoNotAwait() that does nothing. This will not only suppress all warnings, ReSharper or otherwise, but makes the code more understandable, and indicates to future maintainers of your code that you really intended for the call to not be awaited.
我的解决方案是创建一个 Task 的扩展方法,称为 DoNotAwait() ,它什么也不做。这不仅会抑制所有警告、ReSharper 或其他警告,还会使代码更易于理解,并向代码的未来维护者表明您确实打算不等待调用。
Extension method:
扩展方法:
public static class TaskExtensions
{
public static void DoNotAwait(this Task task) { }
}
Usage:
用法:
public static void DoStuff()
{
GetNameAsync().DoNotAwait();
MainWorkOfApplicationIDontWantBlocked();
}
Edited to add: this is similar to Jonathan Allen's solution where the extension method would start the task if not already started, but I prefer to have single-purpose functions so that the caller's intent is completely clear.
编辑添加:这类似于 Jonathan Allen 的解决方案,其中扩展方法将在尚未启动的情况下启动任务,但我更喜欢具有单一用途的功能,以便调用者的意图完全明确。
回答by Jens
Do you really want to ignore the result? as in including ignoring any unexpected exceptions?
你真的要忽略结果吗?包括忽略任何意外的异常?
If not you might want a look at this question: Fire and Forget approach,
如果不是,你可能想看看这个问题:Fire and Forget approach,
回答by JuanluElGuerre
Here, a simple solution.
在这里,一个简单的解决方案。
public static class TasksExtensions
{
public static void RunAndForget(this Task task)
{
}
}
Regards
问候
回答by Simon Mourier
If you don't want to change the method signature to return void
(as returning void
should always be avoided), you can use C# 7.0+ Discard featurelike this, which is slightly better than assigning to a variable (and should remove most other source validation tools warnings):
如果您不想更改要返回的方法签名void
(因为返回void
应该始终是voided),您可以使用 C# 7.0+ 这样的丢弃功能,这比分配给变量稍好(并且应该删除大多数其他源验证工具警告):
public static void DoStuff()
{
_ = GetNameAsync(); // we don't need the return value (suppresses warning)
MainWorkOfApplicationIDontWantBlocked();
}