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
|
## Examples of patterns that are flagged by this analyzer
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
void DoSomething() {
|
void DoSomething()
|
||||||
|
{
|
||||||
DoSomethingElseAsync().Wait();
|
DoSomethingElseAsync().Wait();
|
||||||
DoSomethingElseAsync().GetAwaiter().GetResult();
|
DoSomethingElseAsync().GetAwaiter().GetResult();
|
||||||
var result = CalculateSomethingAsync().Result;
|
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. 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.
|
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.
|
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
|
[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
|
## Examples of patterns that are flagged by this analyzer
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
private void CallVS() {
|
private void CallVS()
|
||||||
|
{
|
||||||
IVsSolution sln = GetIVsSolution();
|
IVsSolution sln = GetIVsSolution();
|
||||||
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
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.
|
UI thread.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
private void CallVS() {
|
private void CallVS()
|
||||||
|
{
|
||||||
ThreadHelper.ThrowIfNotOnUIThread();
|
ThreadHelper.ThrowIfNotOnUIThread();
|
||||||
IVsSolution sln = GetIVsSolution();
|
IVsSolution sln = GetIVsSolution();
|
||||||
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CallVSAsync() {
|
private async Task CallVSAsync()
|
||||||
|
{
|
||||||
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
|
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
|
||||||
IVsSolution sln = GetIVsSolution();
|
IVsSolution sln = GetIVsSolution();
|
||||||
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
sln.SetProperty(); // This analyzer will report warning on this invocation.
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
# VSSDK003 Avoid `async void` methods
|
# 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 of patterns that are flagged by this analyzer
|
||||||
|
|
||||||
{Examples}
|
```csharp
|
||||||
|
async void DoSomethingAsync()
|
||||||
|
{
|
||||||
|
await SomethingElseAsync();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Solution
|
## 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
|
# 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 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
|
||||||
|
|
||||||
{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
|
# 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 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
|
||||||
|
|
||||||
{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.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
Загрузка…
Ссылка в новой задаче