To nie jest duplikat „Jak bezpiecznie wywołać metodę asynchroniczną w języku C # bez oczekiwania” .
Jak ładnie ukryć poniższe ostrzeżenie?
ostrzeżenie CS4014: Ponieważ to wywołanie nie jest oczekiwane, wykonywanie bieżącej metody jest kontynuowane przed zakończeniem wywołania. Rozważ zastosowanie operatora „await” do wyniku wywołania.
Prosty przykład:
static async Task WorkAsync()
{
await Task.Delay(1000);
Console.WriteLine("Done!");
}
static async Task StartWorkAsync()
{
WorkAsync(); // I want fire-and-forget
// more unrelated async/await stuff here, e.g.:
// ...
await Task.Delay(2000);
}
Co próbowałem i nie podobało się:
static async Task StartWorkAsync()
{
#pragma warning disable 4014
WorkAsync(); // I want fire-and-forget here
#pragma warning restore 4014
// ...
}
static async Task StartWorkAsync()
{
var ignoreMe = WorkAsync(); // I want fire-and-forget here
// ...
}
Zaktualizowano , ponieważ pierwotnie zaakceptowana odpowiedź została edytowana, zmieniłem zaakceptowaną odpowiedź na tę, która używa odrzuconych C # 7.0 , ponieważ uważam, że nie ContinueWith
jest tu odpowiednia. Ilekroć muszę rejestrować wyjątki dla operacji „wystrzel i zapomnij”, używam bardziej złożonego podejścia zaproponowanego przez Stephena Cleary'ego .
c#
async-await
noseratio
źródło
źródło
#pragma
to nie jest miłe?async void
metody pomocniczej.Odpowiedzi:
Dzięki C # 7 możesz teraz używać odrzutów :
źródło
_ = ...
w moim mózgu.#pragma warning disable CSxxxx
wygląda bardziej brzydko niż odrzucenie;)Możesz utworzyć metodę rozszerzenia, która zapobiegnie pojawieniu się ostrzeżenia. Metoda rozszerzenia może być pusta lub można tam dodać obsługę wyjątków
.ContinueWith()
.Jednak ASP.NET liczy liczbę uruchomionych zadań, więc nie będzie działać z prostym
Forget()
rozszerzeniem wymienionym powyżej i zamiast tego może się nie powieść z wyjątkiem:W przypadku .NET 4.5.2 można to rozwiązać za pomocą
HostingEnvironment.QueueBackgroundWorkItem
:źródło
TplExtensions.Forget
. Pod spodem jest o wiele więcej dobraMicrosoft.VisualStudio.Threading
. Żałuję, że nie udostępniono go do użytku poza pakietem Visual Studio SDK.Możesz ozdobić metodę następującym atrybutem:
Zasadniczo mówisz kompilatorowi, że wiesz, co robisz i nie musisz się martwić o możliwy błąd.
Ważną częścią tego kodu jest drugi parametr. Część „CS4014:” pomija ostrzeżenie. W pozostałej części możesz napisać, co chcesz.
źródło
[SuppressMessage("Compiler", "CS4014")]
pomija komunikat w oknie Lista błędów, ale okno Wyjście nadal wyświetla wiersz ostrzeżeniaMoje dwa sposoby radzenia sobie z tym.
Zapisz go w zmiennej discard (C # 7)
Przykład
_ = Task.Run(() => DoMyStuff()).ConfigureAwait(false);
Od czasu wprowadzenia odrzutów w C # 7, teraz uważam, że jest to lepsze niż wyłączenie ostrzeżenia. Ponieważ nie tylko tłumi ostrzeżenie, ale także sprawia, że zamiar ognia i zapomnienia jest jasny.
Ponadto kompilator będzie mógł go zoptymalizować w trybie wydania.
Po prostu stłum to
jest wystarczająco dobrym rozwiązaniem, aby „odpalić i zapomnieć”.
Powodem, dla którego istnieje to ostrzeżenie, jest to, że w wielu przypadkach nie jest Twoim zamiarem użycie metody, która zwraca zadanie bez czekania na to. Powstrzymywanie ostrzeżenia, gdy zamierzasz strzelać i zapomnieć, ma sens.
Jeśli masz problemy z zapamiętaniem pisowni
#pragma warning disable 4014
, po prostu pozwól programowi Visual Studio dodać to za Ciebie. Naciśnij Ctrl +. aby otworzyć „Szybkie akcje”, a następnie „Pomiń CS2014”W sumie
Głupotą jest tworzenie metody, której wykonanie wymaga jeszcze kilku tików, tylko w celu zniesienia ostrzeżenia.
źródło
[MethodImpl(MethodImplOptions.AggressiveInlining)] void Forget(this Task @this) { } /* ... */ obj.WorkAsync().Forget();
AggressiveInlining
kompilatora, po prostu go ignoruje z dowolnego powodu#pragma warning disable 4014
a następnie przywrócić ostrzeżenie za pomocą#pragma warning restore 4014
. Nadal działa bez kodu błędu, ale jeśli nie dodasz numeru błędu, pominie wszystkie komunikaty.Łatwym sposobem na zatrzymanie ostrzeżenia jest po prostu przypisanie zadania podczas jego wywoływania:
I tak w swoim oryginalnym poście zrobiłbyś:
źródło
task
wygląda jak zapomniana zmienna lokalna. Prawie tak, jak kompilator powinien dać mi kolejne ostrzeżenie, coś w stylu „task
jest przypisane, ale jego wartość nigdy nie jest używana”, poza tym nie. Ponadto sprawia, że kod jest mniej czytelny. Sam stosuję to podejście.fireAndForget
... więc spodziewam się, że odtąd nie będzie miało odniesienia.Przyczyną ostrzeżenia jest to,
Task
że WorkAsync zwraca komunikat, który nigdy nie jest odczytywany ani oczekiwany. Możesz ustawić zwracany typ WorkAsync na,void
a ostrzeżenie zniknie.Zazwyczaj metoda zwraca a,
Task
gdy wywołujący musi znać status procesu roboczego. W przypadku odpalenia i zapomnienia, void powinien zostać zwrócony, aby przypominał, że wywołujący jest niezależny od wywoływanej metody.źródło
Dlaczego nie zawinąć go w metodę asynchroniczną, która zwraca wartość void? Trochę za długie, ale używane są wszystkie zmienne.
źródło
Dziś znalazłem to podejście przez przypadek. Możesz zdefiniować delegata i najpierw przypisać metodę asynchroniczną do delegata.
i tak to nazwij
...
Pomyślałem, że to interesujące, że kompilator nie dałby dokładnie tego samego ostrzeżenia podczas korzystania z delegata.
źródło
(new Func<Task>(AsyncOperation))()
chociaż IMO nadal jest zbyt szczegółowe.