This commit is contained in:
Andrew Arnott 2016-12-03 15:38:23 -08:00
Родитель 145511bb77
Коммит c797bb0f65
5 изменённых файлов: 130 добавлений и 13 удалений

Просмотреть файл

@ -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.
}
```