Condividi tramite


Risolvere gli errori e gli avvisi nei metodi asincroni che usano l'operatore await

Questo articolo illustra gli errori del compilatore seguenti:

  • CS1983: poiché si tratta di un metodo asincrono, l'espressione restituita deve essere di tipo 'T' anziché 'Task<T>'.
  • CS1985: Non si può attendere in una clausola catch.
  • CS1986: 'await' richiede che il tipo disponga di un metodo 'GetAwaiter' appropriato.
  • CS1989: le espressioni lambda asincrone non possono essere convertite in alberi delle espressioni.
  • CS1991: 'Type' non può implementare 'event' perché si tratta di un evento di Windows Runtime e 'event' è un normale evento .NET.
  • CS1992: l'operatore 'await' può essere usato solo quando è contenuto all'interno di un metodo o di un'espressione lambda contrassegnata con il modificatore "asincrono".
  • CS1994: il modificatore 'async' può essere usato solo nei metodi con un corpo.
  • CS1995: l'operatore 'await' può essere usato solo in un'espressione di query all'interno della prima espressione di raccolta della clausola 'from' iniziale o all'interno dell'espressione di raccolta di una clausola 'join'.
  • CS1996: Impossibile usare 'await' nel corpo di un'istruzione lock.
  • CS1997: poiché la funzione è un metodo asincrono che restituisce un valore, una parola chiave return non deve essere seguita da un'espressione oggetto.
  • CS1998: questo metodo asincrono non dispone di operatori 'await' e verrà eseguito in modo sincrono. Prendere in considerazione l'uso dell'operatore 'await' per attendere le chiamate API non bloccate o 'await Task.Run(...)' per eseguire operazioni associate alla CPU in un thread in background.
  • CS4001: Impossibile attendere l'espressione.
  • CS4003: 'await' non può essere usato come identificatore all'interno di un metodo asincrono o di un'espressione lambda.
  • CS4005: i metodi asincroni non possono avere parametri di tipo puntatore.
  • CS4006: __arglist non è consentito nell'elenco dei parametri dei metodi asincroni.
  • CS4007: L'istanza del tipo non può essere conservata oltre il limite 'await' o 'yield'.
  • CS4008: impossibile attendere 'void'.
  • CS4009: Un punto di ingresso che restituisce void o int non può essere asincrono.
  • CS4010: impossibile convertire un'espressione asincrona in un tipo delegato. Un'espressione asincrona può restituire void, Task o Task<T>, nessuno dei quali è convertibile nel tipo.
  • CS4011: 'await' richiede che il tipo restituito di '{1}.GetAwaiter()' abbia i membri 'IsCompleted', 'OnCompleted' e 'GetResult' e implementi 'INotifyCompletion' o 'ICriticalNotifyCompletion'.
  • CS4012: i parametri di tipo non possono essere dichiarati in metodi asincroni o espressioni lambda asincrone.
  • CS4014: poiché questa chiamata non è attesa, l'esecuzione del metodo corrente continua prima del completamento della chiamata. Valutare la possibilità di applicare l'operatore await al risultato della chiamata.
  • CS4015: 'MethodImplOptions.Synchronized' non può essere applicato a un metodo asincrono.
  • CS4016: Poiché si tratta di un metodo asincrono, l'espressione restituita deve essere di un tipo simile a Task anziché il tipo dichiarato.
  • CS4027: Il tipo espressione non implementa il membro richiesto.
  • CS4028: 'await' richiede che il tipo disponga di un metodo 'GetAwaiter' appropriato. Manca una direttiva using per 'System'?
  • CS4029: impossibile restituire un'espressione di tipo 'void'.
  • CS4030: l'attributo di sicurezza non può essere applicato a un metodo asincrono.
  • CS4031: i metodi asincroni non sono consentiti in un'interfaccia, una classe o una struttura con l'attributo 'SecurityCritical' o 'SecuritySafeCritical'.
  • CS4032: l'operatore 'await' può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore "asincrono" e di modificarne il tipo restituito in "Task<T>".
  • CS4033: l'operatore 'await' può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore 'async' e di modificarne il tipo restituito in 'Task'.
  • CS4034: l'operatore 'await' può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore "asincrono".
  • CS8031: Un'espressione lambda asincrona convertita in un delegato che restituisce un Task non può restituire un valore.
  • CS8100: l'operatore 'await' non può essere usato in un inizializzatore di variabile di script statico.
  • CS8177: I metodi asincroni non possono avere variabili locali per riferimento.
  • CS8178: un riferimento restituito da una chiamata al metodo non può essere mantenuto attraverso il limite 'await' o 'yield'.
  • CS8204: per il tipo da usare come AsyncMethodBuilder per la destinazione del tipo, la relativa proprietà Task deve restituire il tipo di destinazione anziché il tipo dichiarato.
  • CS8403: il metodo con un blocco iteratore deve essere 'async' per restituire IAsyncEnumerable<T>.
  • CS8411: l'istruzione foreach asincrona non può operare su variabili di tipo perché il tipo non contiene un'istanza pubblica o una definizione di estensione appropriata per il membro richiesto.
  • CS8892: il metodo non verrà usato come punto di ingresso perché è stato trovato un punto di ingresso sincrono.
  • CS8935: l'attributo AsyncMethodBuilder non è consentito nei metodi anonimi senza un tipo restituito esplicito.
  • CS8940: Era previsto un tipo di ritorno generico simile a un'attività, ma il tipo trovato nell'attributo 'AsyncMethodBuilder' non è risultato adatto. Deve essere un tipo generico non vincolato di arità 1 e il tipo contenitore (se presente) deve essere non generico.
  • CS9123: l'operatore '&' non deve essere usato nei parametri o nelle variabili locali nei metodi asincroni.
  • CS9330: 'MethodImplAttribute.Async' non può essere applicato manualmente ai metodi. Contrassegnare il metodo 'async'.

Requisiti dell'espressione Await

  • CS1985: Impossibile utilizzare 'await' in una clausola catch.
  • CS1986: 'await' richiede che il tipo disponga di un metodo 'GetAwaiter' appropriato.
  • CS1992: l'operatore 'await' può essere usato solo quando è contenuto all'interno di un metodo o di un'espressione lambda contrassegnata con il modificatore 'async'.
  • CS1995: l'operatore 'await' può essere usato solo in un'espressione di query all'interno della prima espressione di raccolta della clausola 'from' iniziale o all'interno dell'espressione di raccolta di una clausola 'join'.
  • CS1996: Non è possibile usare 'await' nel corpo di un'istruzione di blocco (lock statement).
  • CS4008: impossibile attendere 'void'.
  • CS4032: l'operatore 'await' può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore 'async' e di modificarne il tipo restituito in 'Task<T>'.
  • CS4033: l'operatore 'await' può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore 'async' e di modificarne il tipo restituito in 'Task'.
  • CS4034: l'operatore 'await' può essere usato solo all'interno di un metodo asincrono. Valutare la possibilità di contrassegnare questo metodo con il modificatore "asincrono".
  • CS8178: un riferimento restituito da questa chiamata non può essere mantenuto attraverso il limite 'await' o 'yield'.
  • CS8411: l'istruzione foreach asincrona non può operare su variabili di tipo perché il tipo non contiene un'istanza pubblica o una definizione di estensione appropriata per il membro richiesto.
  • CS4001: Impossibile attendere l'espressione.
  • CS4003: 'await' non può essere usato come identificatore all'interno di un metodo asincrono o di un'espressione lambda.
  • CS4007: l'istanza di tipo non può essere mantenuta attraverso il limite 'await' o 'yield'.
  • CS4011: 'await' richiede che il tipo restituito di 'GetAwaiter()' disponga di membri appropriati di 'IsCompleted', 'OnCompleted' e 'GetResult' e implementa 'INotifyCompletion' o 'ICriticalNotifyCompletion'.
  • CS4027: il tipo non implementa il membro obbligatorio.
  • CS4028: 'await' richiede che il tipo disponga di un metodo 'GetAwaiter' appropriato. Manca una direttiva using per 'System'?
  • CS8100: l'operatore 'await' non può essere usato in un inizializzatore di variabile di script statico.

Gli elementi seguenti illustrano come correggere ogni errore. Per altre informazioni sull'operatoreawait e sul modello awaiter, vedere Programmazione asincrona con async e await.

  • Aggiungere il async modificatore al metodo o all'espressione lambda che contiene l'espressione await (CS1992, CS4032, CS4033, CS4034). Il compilatore richiede il async modificatore in modo che possa generare la macchina a stati che gestisce la sospensione asincrona e la ripresa. Le tre varianti di questo errore forniscono suggerimenti specifici del contesto per il tipo restituito corretto.
  • Spostare le espressioni await dai blocchi catch quando si destina a C# 5 o versioni precedenti (CS1985). A partire da C# 6, il compilatore supporta await sia nei blocchi catch che nei blocchi finally. Questo errore non viene più generato in C# 6 e versioni successive.
  • Spostare le espressioni da blocchi di await (lock). La sospensione asincrona mentre si mantiene un blocco comporta il rischio di deadlock. Il blocco viene mantenuto tra commutatori di thread in cui altro codice potrebbe essere in attesa dello stesso blocco.
  • Ristrutturare le espressioni di query in modo che await compaia solo nella prima espressione di raccolta della clausola iniziale from o nell'espressione di raccolta di una join clausola (CS1995). Altre clausole di query si traducono in espressioni lambda che non supportano la sospensione asincrona.
  • Modificare il tipo dell'espressione attesa in modo che esponga un metodo accessibile GetAwaiter() che segue il modello awaiter (CS1986, CS4028). Il tipo può implementare il modello direttamente o tramite un metodo di estensione. Se il GetAwaiter metodo esiste ma manca una using direttiva per System, il compilatore genera il messaggio CS4028 più specifico anziché CS1986.
  • Verificare che il tipo awaiter restituito da GetAwaiter() abbia IsCompletedmembri , OnCompletede GetResult e implementi INotifyCompletion o ICriticalNotifyCompletion (CS4011, CS4027). L'espressioneawait dipende da questi membri per controllare lo stato di completamento, registrare le continuazioni e recuperare i risultati.
  • Modificare il tipo restituito del metodo chiamato da void a Task o Task<TResult> in modo che il risultato possa essere atteso (CS4008). Non è possibile attendere un metodo che restituisce void perché non esiste alcun oggetto task per monitorare il completamento o propagare le eccezioni.
  • Modificare l'espressione attesa in un tipo che supporta il modello awaiter (CS4001). I tipi come int, stringe altri tipi predefiniti non hanno un GetAwaiter metodo e non possono essere attesi direttamente.
  • Archiviare il risultato di una chiamata al metodo che restituisce ref in una variabile locale prima di usare await (CS8178). Un riferimento restituito da un metodo non può essere conservato attraverso un await confine, perché la macchina a stati asincrona potrebbe sospendersi e riprendere su un thread o contesto diverso, invalidando il riferimento.
  • Implementare IAsyncEnumerable<T> nel tipo di raccolta o aggiungere un metodo accessibile GetAsyncEnumerator che restituisce un tipo con membri Current e MoveNextAsync (CS8411). L'istruzioneawait foreach richiede che il tipo di raccolta segua il modello enumerabile asincrono.
  • Rinominare qualsiasi variabile o parametro locale denominato await all'interno di un metodo o di un'espressione async lambda (CS4003). All'interno di contesti asincroni, await è una parola chiave contestuale e non può essere usata come identificatore.
  • Spostare l'espressione dall'inizializzatore await della variabile di script statica al corpo di un metodo (CS8100). Gli inizializzatori statici vengono eseguiti all'esterno di un contesto asincrono, quindi await non sono disponibili in tale posizione.
  • Ristrutturare il codice in modo che non sia necessario mantenere le istanze ref struct oltre un confine await o yield (CS4007). La macchina async state archivia le variabili locali nell'heap e ref struct i tipi sono associati allo stack in base alla progettazione. Non possono essere spostate in modo sicuro nell'archivio heap tra punti di sospensione.

Requisiti di firma del metodo asincrono

  • CS1983: poiché si tratta di un metodo asincrono, l'espressione restituita deve essere di tipo 'T' anziché 'Task<T>'.
  • CS1994: il modificatore 'async' può essere usato solo nei metodi con un corpo.
  • CS4009: Un punto di ingresso che restituisce void o int non può essere asincrono.
  • CS8892: il metodo non verrà usato come punto di ingresso perché è stato trovato un punto di ingresso sincrono.
  • CS8935: l'attributo AsyncMethodBuilder non è consentito nei metodi anonimi senza un tipo restituito esplicito.
  • CS8940: è previsto un tipo restituito generico simile a 'Task', ma il tipo trovato nell'attributo 'AsyncMethodBuilder' non è adatto. Deve essere un tipo generico non vincolato di arità 1 e il tipo contenitore (se presente) deve essere non generico.
  • CS8403: il metodo con un blocco iteratore deve essere 'async' per restituire '{1}'.
  • CS9330: 'MethodImplAttribute.Async' non può essere applicato manualmente ai metodi. Contrassegnare il metodo 'async'.
  • CS4005: i metodi asincroni non possono avere parametri di tipo puntatore.
  • CS4006: __arglist non è consentito nell'elenco dei parametri dei metodi asincroni.
  • CS4010: Impossibile convertire l'espressione lambda asincrona nel tipo delegato . Un'espressione lambda asincrona può restituire void, Task o Task<T>, nessuno dei quali è convertibile in un tipo restituito.
  • CS4012: i parametri di tipo non possono essere dichiarati in metodi asincroni o espressioni lambda asincrone.
  • CS4015: 'MethodImplOptions.Synchronized' non può essere applicato a un metodo asincrono.
  • CS4016: Poiché si tratta di un metodo asincrono, l'espressione restituita deve essere di tipo Task anziché di tipo normale.
  • CS8031: Un'espressione lambda asincrona convertita in un delegato che restituisce un Task non può restituire un valore.
  • CS8204: per il tipo da usare come AsyncMethodBuilder per il tipo, la relativa proprietà Task deve restituire il tipo richiesto anziché il tipo dichiarato.

Gli elementi seguenti illustrano come correggere ogni errore. Per ulteriori informazioni sulle dichiarazioni di metodi asincroni, vedere il modificatore async e i tipi restituiti asincroni.

  • Modificare l'espressione restituita in modo che corrisponda al tipo di risultato sottostante del metodo asincrono (CS1983, CS4016). Quando un metodo asincrono restituisce Task<T>, l'istruzione return deve fornire un valore di tipo T, non Task<T>, perché la macchina a stati generata dal compilatore esegue automaticamente il wrapping del valore in un'attività. CS1983 viene visualizzato quando il metodo restituisce Task<T> e l'espressione è T; CS4016 illustra il caso generale in cui il tipo di espressione restituito non corrisponde.
  • Rimuovere il async modificatore dai metodi che non hanno un corpo, ad esempio metodi astratti o dichiarazioni di metodi di interfaccia (CS1994). Il async modificatore richiede un corpo del metodo in modo che il compilatore possa generare l'implementazione della macchina a stati.
  • Modificare il tipo restituito di un punto di ingresso asincrono in Task o Task<TResult> (CS4009). A partire da C# 7.1, il Main metodo può essere async, ma deve restituire Task oTask<int> - async voide async int non sono firme di punto di ingresso valide.
  • Rimuovere o rinominare un punto di ingresso quando il progetto contiene sia un metodo sincrono che un metodo asincrono Main (CS8892). Il compilatore seleziona il punto di ingresso sincrono e genera questo avviso riguardo al candidato asincrono che ignora.
  • Aggiungere un tipo restituito esplicito all'espressione lambda prima di applicare l'attributo [AsyncMethodBuilder] (CS8935). Il compilatore non può risolvere il tipo di generatore per un metodo anonimo il cui tipo restituito viene dedotto, perché l'attributo deve essere associato a un tipo restituito specifico in fase di compilazione.
  • Modificare il tipo specificato nell'attributo [AsyncMethodBuilder] in un tipo generico non associato di arity one, ad esempio MyTaskMethodBuilder<> anziché MyTaskMethodBuilder<T> un tipo non generico (CS8940). Il tipo contenitore del costruttore, se presente, deve anche essere non generico. Il compilatore richiede questa forma affinché possa costruire il costruttore per qualsiasi tipo di ritorno concreto task-like.
  • Sostituire l'attributo manuale [MethodImpl(MethodImplOptions.Async)] con la async parola chiave nella dichiarazione del metodo (CS9330). Il MethodImplOptions.Async flag è riservato per l'uso del runtime interno e non può essere applicato direttamente nel codice utente.
  • Aggiungere il async modificatore ai metodi che contengono blocchi iteratori e restituire IAsyncEnumerable<T> o IAsyncEnumerator<T> (CS8403). Senza il async modificatore, il compilatore considera il metodo come iteratore sincrono e non può generare la macchina a stati per il flusso asincrono.
  • Rimuovere i parametri di tipo puntatore dai metodi asincroni (CS4005). I puntatori fanno riferimento a percorsi di memoria fissa che non possono essere mantenuti in modo sicuro in punti di sospensione asincroni in cui l'esecuzione potrebbe riprendere in un thread diverso.
  • Rimuovere __arglist dagli elenchi di parametri del metodo asincrono (CS4006). Gli elenchi di argomenti a lunghezza variabile dipendono da convenzioni di chiamata basate su stack, che sono incompatibili con la macchina a stati asincrona allocata dall'heap.
  • Rimuovere refparametri , ino out e parametri di ref struct tipi come Span<T> o ReadOnlySpan<T>, da metodi asincroni o espressioni lambda asincrone (CS4012). Questi tipi di parametro sono associati allo stack e non possono essere acquisiti in modo sicuro nella chiusura della macchina a stato asincrona allocata nell'heap.
  • Modificare il tipo delegato di destinazione in modo che corrisponda al tipo restituito dell'espressione lambda asincrona (CS4010). Un'espressione lambda asincrona può restituire void, Tasko Task<TResult>e il compilatore non può convertirli in tipi delegati arbitrari che prevedono tipi restituiti diversi.
  • Rimuovere l'espressione return da un'espressione lambda asincrona assegnata a un delegato non generico Tasko modificare il tipo delegato in Func<Task<T>> in modo che l'espressione lambda possa restituire un valore (CS8031). Un delegato che restituisce non genericamente Task rappresenta un'operazione asincrona senza risultato, quindi la restituzione di un valore risulta in un errore di corrispondenza di tipo.
  • Rimuovere l'attributo [MethodImpl(MethodImplOptions.Synchronized)] dai metodi asincroni (CS4015). L'opzione Synchronized acquisisce un blocco per l'intera esecuzione del metodo, ma un metodo asincrono sospende e riprende potenzialmente su thread diversi, rendendo la semantica del blocco non definita.
  • Correggere il tipo personalizzato AsyncMethodBuilder in modo che la relativa Task proprietà restituisca lo stesso tipo del tipo restituito dichiarato dal metodo asincrono (CS8204). Il compilatore usa la proprietà del Task generatore per ottenere l'oggetto attività finale, pertanto un'incompatibilità di tipo impedisce il corretto funzionamento della macchina degli stati.

Pratiche asincrone

  • CS1989: le espressioni lambda asincrone non possono essere convertite in alberi delle espressioni.
  • CS1991: 'Type' non può implementare 'event' perché si tratta di un evento di Windows Runtime e 'event' è un normale evento .NET.
  • CS1997: poiché la funzione è un metodo asincrono che restituisce un valore, una parola chiave return non deve essere seguita da un'espressione oggetto.
  • CS1998: questo metodo asincrono non dispone di operatori 'await' e verrà eseguito in modo sincrono. Prendere in considerazione l'uso dell'operatore 'await' per attendere le chiamate API non bloccate o 'await Task.Run(...)' per eseguire operazioni associate alla CPU in un thread in background.
  • CS4014: poiché questa chiamata non è attesa, l'esecuzione del metodo corrente continua prima del completamento della chiamata. Valutare la possibilità di applicare l'operatore await al risultato della chiamata.
  • CS8177: I metodi asincroni non possono avere variabili locali per riferimento.
  • CS9123: l'operatore '&' non deve essere usato nei parametri o nelle variabili locali nei metodi asincroni.
  • CS4029: impossibile restituire un'espressione di tipo 'void'.
  • CS4030: l'attributo di sicurezza non può essere applicato a un metodo asincrono.
  • CS4031: i metodi asincroni non sono consentiti in un'interfaccia, una classe o una struttura con l'attributo 'SecurityCritical' o 'SecuritySafeCritical'.

Gli elementi seguenti illustrano come correggere ogni errore. Per altre informazioni, vedere Programmazione asincrona con async e await e l'operatoreawait .

  • Aggiungere l'operatore await a ogni chiamata che restituisce Task o Task<TResult>oppure rimuovere in modo esplicito il risultato con _ = se il comportamento fire-and-forget è veramente previsto (CS4014). Senza await, qualsiasi eccezione generata dall'operazione asincrona viene persa automaticamente e il metodo chiamante continua l'esecuzione prima del completamento dell'operazione, che può causare bug di ordinamento e correttezza sottili.
  • Rimuovere l'espressione return da un metodo asincrono il cui tipo restituito è Task (non generico) o modificare il tipo restituito in Task<T> quando il metodo deve restituire un valore (CS1997). In un metodo asincrono che restituisce Task, il compilatore genera il wrapper del compito - restituire un valore provoca una discordanza di tipo, perché la firma del metodo non promette alcun risultato.
  • Aggiungi almeno un'espressione await al corpo del metodo o rimuovi il modificatore async e restituisci direttamente l'attività (CS1998). Un async metodo senza await espressioni viene eseguito completamente in modo sincrono, che comporta un sovraccarico della macchina a stati finiti non necessario. Se il metodo avvolge intenzionalmente un'operazione sincrona, la rimozione di async e la restituzione dell'oggetto attività elimina esplicitamente tale overhead.
  • Riscrivere l'espressione lambda in modo che non venga usata async quando viene assegnata a un tipo di albero delle espressioni come Expression<Func<...>> (CS1989). Gli alberi delle espressioni rappresentano il codice come strutture di dati che il compilatore può analizzare o tradurre, ma la macchina a stati complessa che async produce non può essere acquisita in un albero delle espressioni.
  • Modificare l'implementazione dell'evento in modo che sia la dichiarazione di interfaccia che la classe di implementazione accettino se l'evento usa la semantica di Windows Runtime o la normale semantica .NET (CS1991). Questo errore si applica agli scenari di interoperabilità di Windows Runtime in cui un evento WinRT non può essere implementato come normale evento .NET o viceversa.
  • Rimuovere l'operatore address-of (&) dalle espressioni che fanno riferimento a parametri o variabili locali all'interno di metodi asincroni (CS9123). La macchina a stati asincrona potrebbe rilocare le variabili catturate nell'heap durante la sospensione, il che invaliderebbe qualsiasi puntatore ottenuto tramite l'indirizzo di.
  • Rimuovere le variabili locali per riferimento dai metodi asincroni o assicurarsi che non si estendono su un await limite (CS8177). La macchina a stati asincrona acquisisce le variabili locali nelle closures allocate sul heap e i riferimenti alle posizioni nello stack non possono essere conservati in modo sicuro attraverso i punti di sospensione. In C# 13 e versioni successive, le variabili locali ref sono consentite nei metodi asincroni purché non si estenda su un await limite e questo errore non viene generato.
  • Rimuovere l'istruzione return che restituisce il risultato di un voidmetodo -returning oppure modificare il metodo chiamato per restituire un valore (CS4029). Non è possibile usare return SomeVoidMethod(); perché void non è un tipo che può essere restituito come valore. Rimuovere la return parola chiave e chiamare il metodo come istruzione autonoma oppure modificare la firma del metodo chiamato per restituire un tipo concreto.
  • Rimuovere attributi di sicurezza come [SecurityCritical] o [SecuritySafeCritical] da metodi asincroni (CS4030) o rimuovere il async modificatore dai metodi nei tipi contrassegnati con questi attributi (CS4031). Le annotazioni di sicurezza per l'accesso al codice si applicano al metodo dichiarante, ma la macchina a stati asincrona generata dal compilatore viene eseguita in un contesto separato in cui tali annotazioni di sicurezza non possono essere applicate.