Docs for VSSDK001-005
This commit is contained in:
Родитель
145511bb77
Коммит
c797bb0f65
|
@ -5,7 +5,8 @@ Synchronously waiting on `Task` objects or awaiters is dangerous and may cause d
|
|||
## Examples of patterns that are flagged by this analyzer
|
||||
|
||||
```csharp
|
||||
void DoSomething() {
|
||||
void DoSomething()
|
||||
{
|
||||
DoSomethingElseAsync().Wait();
|
||||
DoSomethingElseAsync().GetAwaiter().GetResult();
|
||||
var result = CalculateSomethingAsync().Result;
|
||||
|
@ -20,6 +21,25 @@ Please consider the following options:
|
|||
1. Change the chain of callers to be "async" methods, and then change this code to be asynchronous await.
|
||||
1. Use `JoinableTaskFactory.Run()` to wait on the tasks or awaiters.
|
||||
|
||||
```csharp
|
||||
async Task DoSomethingAsync()
|
||||
{
|
||||
await DoSomethingElseAsync();
|
||||
await DoSomethingElseAsync();
|
||||
var result = await CalculateSomethingAsync();
|
||||
}
|
||||
|
||||
void DoSomething()
|
||||
{
|
||||
joinableTaskFactory.Run(async delegate
|
||||
{
|
||||
await DoSomethingElseAsync();
|
||||
await DoSomethingElseAsync();
|
||||
var result = await CalculateSomethingAsync();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Refer to [Asynchronous and multithreaded programming within VS using the JoinableTaskFactory][1] for more information.
|
||||
|
||||
[1]: http://blogs.msdn.com/b/andrewarnottms/archive/2014/05/07/asynchronous-and-multithreaded-programming-within-vs-using-the-joinabletaskfactory.aspx
|
||||
|
|
|
@ -6,7 +6,8 @@ that your code is running on the UI thread.
|
|||
## Examples of patterns that are flagged by this analyzer
|
||||
|
||||
```csharp
|
||||
private void CallVS() {
|
||||
private void CallVS()
|
||||
{
|
||||
IVsSolution sln = GetIVsSolution();
|
||||
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
||||
}
|
||||
|
@ -19,13 +20,15 @@ Either throw when you are not on the appropriate thread, or explicitly switch to
|
|||
UI thread.
|
||||
|
||||
```csharp
|
||||
private void CallVS() {
|
||||
private void CallVS()
|
||||
{
|
||||
ThreadHelper.ThrowIfNotOnUIThread();
|
||||
IVsSolution sln = GetIVsSolution();
|
||||
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
||||
}
|
||||
|
||||
private async Task CallVSAsync() {
|
||||
private async Task CallVSAsync()
|
||||
{
|
||||
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
|
||||
IVsSolution sln = GetIVsSolution();
|
||||
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
||||
|
|
|
@ -1,11 +1,27 @@
|
|||
# VSSDK003 Avoid `async void` methods
|
||||
|
||||
{Explanation}
|
||||
Methods with `async void` signatures make it impossible for their caller to track
|
||||
the entire asynchronous operation and handle exceptions that may be thrown by that method.
|
||||
If the method throws an exception, it crashes the process.
|
||||
|
||||
## Examples of patterns that are flagged by this analyzer
|
||||
|
||||
{Examples}
|
||||
```csharp
|
||||
async void DoSomethingAsync()
|
||||
{
|
||||
await SomethingElseAsync();
|
||||
}
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
{Solution}
|
||||
Change the method to return `Task` instead of `void`.
|
||||
|
||||
```csharp
|
||||
async Task DoSomethingAsync()
|
||||
{
|
||||
await SomethingElseAsync();
|
||||
}
|
||||
```
|
||||
|
||||
A code fix is offered that automatically changes the return type of the method.
|
||||
|
|
|
@ -1,11 +1,69 @@
|
|||
# VSSDK004 Avoid unsupported async delegates
|
||||
|
||||
{Explanation}
|
||||
C# allows you to define async delegates or lambdas and use them in contexts that accept
|
||||
void-returning delegates, thus creating an `async void` method such as is forbidden by
|
||||
[VSSDK003](VSSDK003.md), but is much harder to catch when simply looking at the code
|
||||
because for the same syntax, the C# compiler will create an `async Func<Task>` delegate
|
||||
or an `async void` delegate based on the type expected by the method being invoked.
|
||||
|
||||
This analyzer helps prevent inadvertent creation of `async void` delegates.
|
||||
|
||||
## Examples of patterns that are flagged by this analyzer
|
||||
|
||||
{Examples}
|
||||
```csharp
|
||||
void StartWatching(ObservableCollection<string> oc)
|
||||
{
|
||||
// This delegate becomes an "async void" method to match the EventHandler delegate type.
|
||||
oc.CollectionChanged += async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
};
|
||||
}
|
||||
|
||||
void StartWatching(ObservableCollection<string> oc)
|
||||
{
|
||||
// This delegate becomes an "async void" method to match the Action delegate type.
|
||||
Callback(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
});
|
||||
}
|
||||
|
||||
void Callback(Action action)
|
||||
{
|
||||
// out of scope of sample
|
||||
}
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
{Solution}
|
||||
1. Wrap the asynchronous behavior in another method that accepts a `Func<Task>` delegate.
|
||||
1. Change the receiving method's expected delegate type to one that returns a `Task` or `Task<T>`.
|
||||
1. Implement the delegate synchronously.
|
||||
|
||||
```csharp
|
||||
void StartWatching(ObservableCollection<string> oc)
|
||||
{
|
||||
oc.CollectionChanged += () =>
|
||||
{
|
||||
// The outer delegate is synchronous, but kicks off async work via a method that accepts an async delegate.
|
||||
joinableTaskFactory.RunAsync(async delegate {
|
||||
await Task.Yield();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
void StartWatching(ObservableCollection<string> oc)
|
||||
{
|
||||
// This delegate becomes an "async Task" method to match the Func<Task> delegate type.
|
||||
Callback(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
});
|
||||
}
|
||||
|
||||
void Callback(Func<Task> action)
|
||||
{
|
||||
// out of scope of sample
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,11 +1,31 @@
|
|||
# VSSDK005 Use `InvokeAsync` to raise async events
|
||||
|
||||
{Explanation}
|
||||
Asynchronous events (those typed as `AsyncEventHandler`) must be raised carefully to ensure
|
||||
all event handlers are invoked and awaited on.
|
||||
|
||||
Although C# lets you invoke event handlers naturally, it has no awareness of async event handlers
|
||||
and thus will not let you correctly await on their invocation nor invoke them sequentially.
|
||||
|
||||
## Examples of patterns that are flagged by this analyzer
|
||||
|
||||
{Examples}
|
||||
```csharp
|
||||
public AsyncEventHandler Clicked;
|
||||
|
||||
async Task OnClicked() {
|
||||
await Clicked(this, EventArgs.Empty); // only awaits the first event handler.
|
||||
}
|
||||
```
|
||||
|
||||
## Solution
|
||||
|
||||
{Solution}
|
||||
Use the `InvokeAsync` extension method defined in the `TplExtensions` class and await its result.
|
||||
This will ensure each event handler completes before invoking the next event handler in the list,
|
||||
similar to the default behavior for raising synchronous events.
|
||||
|
||||
```csharp
|
||||
public AsyncEventHandler Clicked;
|
||||
|
||||
async Task OnClicked() {
|
||||
await Clicked.InvokeAsync(this, EventArgs.Empty); // await for the completion of all handlers.
|
||||
}
|
||||
```
|
||||
|
|
Загрузка…
Ссылка в новой задаче