2015-09-24 5 views
7

Visual Studio emette un avviso per questo codice ('poiché questa chiamata non è attesa, l'esecuzione del metodo corrente continua prima che la chiamata sia completata').È corretto dichiarare un metodo asincrono come invalido per disattivare l'avviso CS4014?

static void Main(string[] args) 
{ 
    FireAndForget(); // <-- Warning CS4014 
    // Do something else. 
} 

static async Task FireAndForget() 
{ 
    // Do something (cannot throw). 
} 

La mia comprensione è che è OK di non aspettare per il compito in questo caso particolare, perché non sarà mai FireAndForget un'eccezione.

Invece di disattivare l'avviso con un pragma, stavo considerando di cambiare il tipo di ritorno di FireAndForget da Task a void. Questo attenua efficacemente il compilatore.

static async void FireAndForget() // <-- Task changed to void 
{ 
    // Do something (cannot throw). 
} 

Tuttavia, secondo Stephen Cleary, metodi di 'vuoto' asincrone dovrebbero essere evitati, quindi non sono del tutto sicuri di cosa fare.

È corretto avere un metodo "async void" se il metodo non è progettato per essere attendibile in primo luogo e se non verrà lanciata alcuna eccezione?

+0

* il metodo non è progettato per essere attendibile in primo luogo * Che cosa significa? Cosa fa effettivamente "FireAndForget"? –

+3

Perché diamine è stato questo downvoted + votato per la chiusura? – ken2k

+0

@ ken2k Non ho votato per chiudere ma posso vedere dove questo sarebbe visto come una domanda basata sull'opinione senza una risposta obiettivamente corretta. Forse "Va bene" potrebbe essere riformulato in "Quali sono i vantaggi e gli svantaggi". – pseudocoder

risposta

9

È estremamente raro avere una vera operazione fire-and-forget; cioè, un'operazione in cui:

  • A nessuno importa quando si completa.
  • A nessuno importa se completa.
  • A nessuno importa se lancia un'eccezione.

In particolare con l'ultimo di questi; la maggior parte delle cosiddette operazioni "fire-and-forget" non sono in realtà fire-and-forget perché alcune azioni devono essere intraprese se non ci riesce.

Detto questo, ci sono alcune situazioni in cui è applicabile un vero fuoco-e-dimentica.

preferisco usare async Task ed evitare l'avviso del compilatore assegnando il compito di una variabile altrimenti inutilizzato:

var _ = FireAndForget(); 

async Task metodi sono più riutilizzabili e verificabili rispetto async void metodi.

Tuttavia, non vorrei fare un tentativo se uno sviluppatore della mia squadra usasse solo async void.

+0

Trovo difficile credere che dovrebbe essere così raro. Senza i metodi fire-and-forget, "async" non diventerebbe virale e si propagherebbe al metodo Main (dove si dovrebbe "Wait")? – ZunTzu

+0

Stephen, ho un'altra domanda. Ho provato ad assegnare l'attività a una variabile come nell'esempio. Effettivamente fa tacere il compilatore, ma l'attività non è ancora attesa. Non dovrebbe anche il compilatore emettere un avviso in quel caso? – ZunTzu

+1

@ZunTzu: 1) Sì; questo è il modo in cui funzionano la maggior parte (> 98%) dei programmi asincroni. 2) Il compilatore fa del suo meglio per avvisare ma non è (non può essere) perfetto. –

2

Va bene avere un metodo 'async vuoto' se il metodo non è progettato per essere awaitable in primo luogo e se non fa eccezione saranno gettati?

Sebbene possa essere "OK" per farlo, ti incoraggerei comunque a eseguire il metodo async Task. Anche se sei sicuro al cento per cento che questo metodo non possa essere gettato e non sia atteso, non sai mai come potrebbe essere usato. Ora sei pienamente consapevole di quali sono le conseguenze dell'utilizzo di async void, ma se c'è una piccola possibilità che qualcuno possa aver bisogno di usarlo in futuro, allora è meglio mettere un bel commento sul motivo per cui questo Task non viene atteso invece di andare con il percorso facile di fare questo void.

Non lasciare che gli avvisi del compilatore ti preoccupino, direi che preoccuparsi della correttezza e degli effetti che questo potrebbe avere sul codice base.

+0

Cambiare "vuoto" in "Attività" solo perché il metodo è "asincrono" è sbagliato. Ecco perché L'unico scopo di "asincrono" è quello di sbloccare la possibilità di usare "attendere" nel corpo del metodo. La mia opinione è che significhi 'asincrono' non fa parte del contratto esterno del metodo. Il cambiamento di "vuoto" in "Attività" sul contratto cambia il contratto esterno. – ZunTzu

+0

@ZunTzu Ma espone il vero funzionamento del metodo. Quando vedo un metodo di restituzione "void', presumo che sia sincrono. Il richiamo di un tale metodo che completa ma l'operazione sottostante non è molto più confuso, e probabilmente mentendo al chiamante. –

+0

come regola generale il chiamante non può dire se lancio un thread di lavoro o se chiamo un servizio web. Perché il chiamante dovrebbe sapere se uso "attendere"? Mi sembra una violazione del principio di incapsulamento. – ZunTzu

0

Un potenziale problema è che ora sarà impossibile stabilire se il codice ha generato un'eccezione o meno. Quindi, se sono in atto test unitari per rilevarli, i test unitari non funzioneranno mai.

esempio

Classic dal sito MSDN:

 
private async void ThrowExceptionAsync() 
{ 
    throw new InvalidOperationException(); 
} 
public void AsyncVoidExceptions_CannotBeCaughtByCatch() 
{ 
    try 
    { 
    ThrowExceptionAsync(); 
    } 
    catch (Exception) 
    { 
    // The exception is never caught here! 
    throw; 
    } 
} 

http://haacked.com/archive/2014/11/11/async-void-methods/

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

invece di utilizzare async void, se questo è un caso limite preciso, come su utilizzando le istruzioni pragma?

#pragma warning disable CS-4014 
... your code here ... 
#pragma warning restore CS-4014 

In questo modo è possibile eliminare il rumore statico.

HTH ...

+0

Sono consapevole di questa limitazione. Ecco perché ho scritto esplicitamente che FireAndForget non può generare un'eccezione. – ZunTzu

+0

Sì, l'uso specifico previsto di 'async void' è in realtà per i gestori di eventi, quindi qualsiasi utilizzo esterno dovrebbe essere evitato, IMHO. Usa invece i pragmi. – code4life

Problemi correlati