Compartir a través de


Resolución de errores y advertencias en métodos asincrónicos que usan el operador await

En este artículo se tratan los siguientes errores del compilador:

  • CS1983: Dado que se trata de un método asincrónico, la expresión de retorno debe ser de tipo 'T' en lugar de 'Task<T>'.
  • CS1985: No se puede usar 'await' en un bloque catch.
  • CS1986: 'await' requiere que el tipo tenga un método 'GetAwaiter' adecuado.
  • CS1989: las expresiones lambda asincrónicas no se pueden convertir en árboles de expresión.
  • CS1991: "Type" no puede implementar "event" porque es un evento de Windows Runtime y "event" es un evento de .NET normal.
  • CS1992: el operador 'await' solo se puede usar cuando se incluye dentro de un método o expresión lambda marcada con el modificador 'async'.
  • CS1994: el modificador 'async' solo se puede usar en métodos que tienen un cuerpo.
  • CS1995: el operador 'await' solo se puede usar en una expresión de consulta dentro de la primera expresión de colección de la cláusula inicial 'from' o dentro de la expresión de colección de una cláusula 'join'.
  • CS1996: No se puede utilizar 'await' en el bloque de una instrucción lock.
  • CS1997: Dado que function es un método asincrónico que devuelve un valor, una palabra clave return no debe ir seguida de una expresión de objeto.
  • CS1998: este método asincrónico carece de operadores "await" y se ejecutará sincrónicamente. Considere la posibilidad de usar el operador "await" para esperar llamadas API sin bloqueo o "await Task.Run(...)" para realizar el trabajo enlazado a la CPU en un subproceso en segundo plano.
  • CS4001: no se puede esperar expresión.
  • CS4003: 'await' no se puede usar como identificador dentro de un método asincrónico o una expresión lambda.
  • CS4005: los métodos asincrónicos no pueden tener parámetros de tipo de puntero.
  • CS4006: no se permite __arglist en la lista de parámetros de métodos asincrónicos.
  • CS4007: La instancia de tipo no se puede conservar en el límite "await" o "yield".
  • CS4008: no se puede esperar 'void'.
  • CS4009: un punto de entrada nulo o int que devuelve no puede ser asincrónico.
  • CS4010: no se puede convertir la expresión asincrónica al tipo delegado. Una expresión asincrónica puede devolver void, Task o Task<T>, ninguno de los cuales se puede convertir al tipo.
  • CS4011: 'await' requiere que el tipo de retorno de '{1}.GetAwaiter()' tenga miembros adecuados 'IsCompleted', 'OnCompleted' y 'GetResult', e implemente 'INotifyCompletion' o 'ICriticalNotifyCompletion'.
  • CS4012: Los parámetros de tipo no se pueden declarar en métodos asincrónicos ni expresiones lambda asincrónicas.
  • CS4014: dado que no se espera esta llamada, la ejecución del método actual continúa antes de que se complete la llamada. Considere la posibilidad de aplicar el await operador al resultado de la llamada.
  • CS4015: 'MethodImplOptions.Synchronized' no se puede aplicar a un método asincrónico.
  • CS4016: Dado que se trata de un método asincrónico, la expresión de retorno debe ser de un tipo similar a Task en lugar del tipo declarado.
  • CS4027: el tipo de expresión no implementa el miembro necesario.
  • CS4028: "await" requiere que el tipo disponga de un método "GetAwaiter" adecuado. ¿Falta una directiva using para "System"?
  • CS4029: no se puede devolver una expresión de tipo 'void'.
  • CS4030: El atributo security no se puede aplicar a un método asincrónico.
  • CS4031: los métodos asincrónicos no se permiten en un atributo Interface, Class o Structure que tenga el atributo "SecurityCritical" o "SecuritySafeCritical".
  • CS4032: el operador 'await' solo se puede usar dentro de un método asincrónico. Considere la posibilidad de marcar este método con el modificador "async" y cambiar su tipo de valor devuelto a "Task<T>".
  • CS4033: el operador 'await' solo se puede usar dentro de un método asincrónico. Considere la posibilidad de marcar este método con el modificador 'async' y cambiar su tipo de valor devuelto a 'Task'.
  • CS4034: el operador 'await' solo se puede usar dentro de un método asincrónico. Considere la posibilidad de marcar este método con el modificador "async".
  • CS8031: La expresión lambda asincrónica, al ser convertida en un delegado que devuelve una tarea, no puede devolver un valor.
  • CS8100: el operador 'await' no se puede usar en un inicializador de variable de script estático.
  • CS8177: los métodos asincrónicos no pueden tener variables locales de referencia.
  • CS8178: no se puede conservar una referencia devuelta por una llamada al método a través del límite "await" o "yield".
  • CS8204: Para que el tipo pueda ser utilizado como AsyncMethodBuilder para el tipo objetivo, su propiedad Task debería devolver el tipo objetivo en lugar del tipo declarado.
  • CS8403: el método con un bloque de iterador debe ser 'async' para devolver IAsyncEnumerable<T>.
  • CS8411: la instrucción foreach asincrónica no puede funcionar en variables de tipo porque el tipo no contiene una definición de extensión o instancia pública adecuada para el miembro necesario.
  • CS8892: el método no se usará como punto de entrada porque se encontró un punto de entrada sincrónico.
  • CS8935: El atributo AsyncMethodBuilder no se permite en métodos anónimos sin un tipo de valor devuelto explícito.
  • CS8940: Se esperaba un tipo de retorno genérico similar a una tarea, pero el tipo encontrado en el atributo "AsyncMethodBuilder" no era adecuado. Debe ser un tipo genérico sin vincular con aridad uno, y su tipo contenedor (si existe) debe ser no genérico.
  • CS9123: el operador '&' no debe usarse en parámetros ni variables locales en métodos asincrónicos.
  • CS9330: 'MethodImplAttribute.Async' no se puede aplicar manualmente a los métodos. Marque el método "async".

Requisitos para las expresiones await

  • CS1985: No puede utilizarse 'await' en una cláusula catch.
  • CS1986: 'await' requiere que el tipo tenga un método 'GetAwaiter' adecuado.
  • CS1992: el operador 'await' solo se puede usar cuando se incluye dentro de un método o expresión lambda marcada con el modificador 'async'.
  • CS1995: el operador 'await' solo se puede usar en una expresión de consulta dentro de la primera expresión de colección de la cláusula inicial 'from' o dentro de la expresión de colección de una cláusula 'join'.
  • CS1996: No se puede utilizar await en el cuerpo de una instrucción lock.
  • CS4008: no se puede esperar 'void'.
  • CS4032: el operador 'await' solo se puede usar dentro de un método asincrónico. Considere la posibilidad de marcar este método con el modificador 'async' y cambiar su tipo de valor devuelto a 'Task<T>'.
  • CS4033: el operador 'await' solo se puede usar dentro de un método asincrónico. Considere la posibilidad de marcar este método con el modificador 'async' y cambiar su tipo de valor devuelto a 'Task'.
  • CS4034: el operador 'await' solo se puede usar dentro de un método asincrónico. Considere la posibilidad de marcar este método con el modificador "async".
  • CS8178: no se puede conservar una referencia devuelta por esta llamada a través del límite "await" o "yield".
  • CS8411: la instrucción foreach asincrónica no puede funcionar en variables de tipo porque el tipo no contiene una definición de extensión o instancia pública adecuada para el miembro necesario.
  • CS4001: No se puede usar 'await' en la expresión.
  • CS4003: 'await' no se puede usar como identificador dentro de un método asincrónico o una expresión lambda.
  • CS4007: La instancia de tipo no se puede conservar en el límite "await" o "yield".
  • CS4011: '' requiere que el tipo de valor devuelto de tenga los miembros 'IsCompleted', 'OnCompleted' y 'GetResult' e implemente 'INotifyCompletion' o 'ICriticalNotifyCompletion'.
  • CS4027: El tipo no implementa el miembro requerido.
  • CS4028: "await" requiere que el tipo tenga un método "GetAwaiter" adecuado. ¿Está faltando una directiva "using" para "System"?
  • CS8100: el operador 'await' no se puede usar en un inicializador de variable de script estático.

Los siguientes elementos explican cómo corregir cada error. Para obtener más información sobre el await operador y el patrón awaiter, consulte Programación asincrónica con async y await.

  • Agregue el async modificador al método o expresión lambda que contiene la await expresión (CS1992, CS4032, CS4033, CS4034). El compilador requiere el async modificador para que pueda generar la máquina de estado que controla la suspensión asincrónica y la reanudación. Las tres variantes de este error proporcionan sugerencias específicas del contexto para el tipo de valor devuelto correcto.
  • Mueva await las expresiones fuera de catch los bloques cuando tenga como objetivo C# 5 o versiones anteriores (CS1985). A partir de C# 6, el compilador admite await en bloques catch y finally . Este error ya no se genera en C# 6 y versiones posteriores.
  • Mueva await las expresiones fuera de los bloques de lock declaraciones (CS1996). La suspensión asincrónica mientras mantiene un bloqueo corre el riesgo de interbloqueos. El bloqueo se mantiene entre conmutadores de subproceso donde otro código podría estar esperando el mismo bloqueo.
  • Reestructura las expresiones de consulta para que await solo aparezcan en la primera expresión de colección de la cláusula inicial from o en la expresión de colección de una join cláusula (CS1995). Otras cláusulas de consulta se traducen en expresiones lambda que no admiten suspensión asincrónica.
  • Cambie el tipo de la expresión esperada para que exponga un método accesible GetAwaiter() que siga el patrón awaiter (CS1986, CS4028). El tipo puede implementar el patrón directamente o a través de un método de extensión. Si el GetAwaiter método existe, pero falta una using directiva para System, el compilador genera el mensaje CS4028 más específico en lugar de CS1986.
  • Asegúrese de que el tipo awaiter devuelto por GetAwaiter() tiene IsCompletedmiembros , OnCompletedy GetResult e implementa INotifyCompletion o ICriticalNotifyCompletion (CS4011, CS4027). La await expresión depende de estos miembros para comprobar el estado de finalización, registrar continuaciones y recuperar resultados.
  • Cambie el tipo de valor devuelto del método llamado de void a Task o Task<TResult> para que se pueda esperar el resultado (CS4008). No se puede esperar a un voidmétodo de devolución porque no hay ningún objeto de tarea para realizar un seguimiento de la finalización o propagar excepciones.
  • Cambie la expresión esperada a un tipo que admita el patrón awaiter (CS4001). Los tipos como int, stringy otros tipos integrados no tienen un GetAwaiter método y no se pueden esperar directamente.
  • Almacene el resultado de una llamada al método que devuelve referencias en una variable local antes de usar await (CS8178). Una referencia devuelta por un método no se puede conservar a través de una await frontera porque la máquina de estados asincrónica puede suspenderse y reanudarse en otro hilo o contexto, invalidando la referencia.
  • Implemente IAsyncEnumerable<T> en el tipo de colección o agregue un método accesible GetAsyncEnumerator que devuelva un tipo con Current miembros y MoveNextAsync (CS8411). La await foreach instrucción requiere que el tipo de colección siga el patrón enumerable asincrónico.
  • Cambie el nombre de cualquier variable o parámetro local denominado await dentro de un async método o expresión lambda (CS4003). Dentro de contextos asincrónicos, await es una palabra clave contextual y no se puede usar como identificador.
  • Mueva la await expresión fuera del inicializador de la variable de script estático y a un cuerpo del método (CS8100). Los inicializadores estáticos se ejecutan fuera de un contexto asincrónico, por lo que await no está disponible en esa ubicación.
  • Reestructurar el código de modo que las instancias ref struct no necesiten conservarse a través de un límite await o yield (CS4007). La máquina de estado asincrónica almacena variables locales en el montón, y los tipos ref struct están diseñados para estar ligados a la pila; no se pueden mover de forma segura a la memoria del montón entre puntos de suspensión.

Requisitos de firma de método asíncrono

  • CS1983: Dado que se trata de un método asincrónico, la expresión de retorno debe ser del tipo "T" en lugar de "Task<T>".
  • CS1994: el modificador 'async' solo se puede usar en métodos que tienen un cuerpo.
  • CS4009: un punto de entrada nulo o int que devuelve no puede ser asincrónico.
  • CS8892: el método no se usará como punto de entrada porque se encontró un punto de entrada sincrónico.
  • CS8935: El atributo AsyncMethodBuilder no se permite en métodos anónimos sin un tipo de valor devuelto explícito.
  • CS8940: Se esperaba un tipo genérico de retorno similar a una tarea, pero el tipo encontrado en el atributo 'AsyncMethodBuilder' no era adecuado. Debe ser un tipo genérico no vinculado de aridad uno, y su tipo contenedor (si existe) debe ser no genérico.
  • CS8403: el método con un bloque de iterador debe ser 'async' para devolver '{1}'.
  • CS9330: 'MethodImplAttribute.Async' no se puede aplicar manualmente a los métodos. Marque el método 'async'.
  • CS4005: los métodos asincrónicos no pueden tener parámetros de tipo de puntero.
  • CS4006: no se permite __arglist en la lista de parámetros de métodos asincrónicos.
  • CS4010: No se puede convertir lambda asincrónica al tipo delegado. Una expresión lambda asincrónica puede devolver void, Task o Task<T>, ninguna de las cuales se puede convertir al tipo devuelto.
  • CS4012: Los parámetros de tipo no se pueden declarar en métodos asincrónicos ni expresiones lambda asincrónicas.
  • CS4015: 'MethodImplOptions.Synchronized' no se puede aplicar a un método asincrónico.
  • CS4016: dado que se trata de un método asincrónico, la expresión de retorno debe ser de tipo de tarea en lugar de tipo.
  • CS8031: La expresión lambda asíncrona convertida en un delegado que devuelve tareas no puede devolver un valor.
  • CS8204: Para que un tipo se utilice como AsyncMethodBuilder para otro tipo, su propiedad Task debe devolver el tipo requerido en lugar del tipo declarado.

Los siguientes elementos explican cómo corregir cada error. Para obtener más información sobre las declaraciones de métodos async, consulte el modificador y los tipos de retorno asincrónicos .

  • Cambie la expresión de retorno para que coincida con el tipo de resultado subyacente del método asincrónico (CS1983, CS4016). Cuando un método asincrónico devuelve Task<T>, la return instrucción debe proporcionar un valor de tipo T, no Task<T>, porque la máquina de estado generada por el compilador ajusta automáticamente el valor en un objeto Task. CS1983 aparece cuando el método devuelve Task<T> y la expresión es T; CS4016 cubre el caso general en el que el tipo de expresión de retorno no coincide.
  • Quite el async modificador de los métodos que no tienen un cuerpo, como métodos abstractos o declaraciones de métodos de interfaz (CS1994). El async modificador requiere un cuerpo del método para que el compilador pueda generar la implementación de la máquina de estado.
  • Cambie el tipo de valor devuelto de un punto de entrada asincrónico a Task o Task<TResult> (CS4009). A partir de C# 7.1, el Main método puede ser async, pero debe devolver Task oTask<int> - async voidy async int no son firmas de punto de entrada válidas.
  • Quite o cambie el nombre de un punto de entrada cuando el proyecto contenga un método sincrónico y asincrónico Main (CS8892). El compilador selecciona el punto de entrada sincrónico y emite esta advertencia para el candidato asincrónico que omite.
  • Agregue un tipo de valor devuelto explícito a la expresión lambda antes de aplicar el [AsyncMethodBuilder] atributo (CS8935). El compilador no puede resolver el tipo de generador para un método anónimo cuyo tipo de valor devuelto se infiere, ya que el atributo debe coincidir con un tipo de valor devuelto específico en tiempo de compilación.
  • Cambie el tipo especificado en el atributo [AsyncMethodBuilder] a un tipo genérico sin enlazar como uno de aridad, como MyTaskMethodBuilder<> en lugar de MyTaskMethodBuilder<T> o un tipo no genérico (CS8940). El tipo que contiene el generador, si lo hay, también debe ser no genérico. El compilador requiere esta forma para que pueda construir el patrón para cualquier tipo de retorno de tipo tarea concreto.
  • Reemplace el atributo manual [MethodImpl(MethodImplOptions.Async)] por la async palabra clave en la declaración de método (CS9330). La MethodImplOptions.Async marca está reservada para uso interno en tiempo de ejecución y no se puede aplicar directamente en el código de usuario.
  • Agregue el async modificador a los métodos que contienen bloques de iterador y devuelven IAsyncEnumerable<T> o IAsyncEnumerator<T> (CS8403). Sin el modificador async, el compilador trata el método como el iterador síncrono y no puede generar la máquina de estados para flujos asíncronos.
  • Quite los parámetros de tipo de puntero de los métodos asincrónicos (CS4005). Los punteros hacen referencia a ubicaciones de memoria fijas que no se pueden conservar de forma segura en puntos de suspensión asincrónicos en los que la ejecución podría reanudarse en un subproceso diferente.
  • Quite __arglist de las listas de parámetros del método asincrónico (CS4006). Las listas de argumentos de longitud variable dependen de las convenciones de llamada basadas en la pila que no son compatibles con la máquina de estado asincrónica asignada por el montón.
  • Quite los parámetros ref, in o out, y los parámetros de tipos ref struct como Span<T> o ReadOnlySpan<T>, de métodos asincrónicos o expresiones lambda asincrónicas (CS4012). Estos tipos de parámetros están enlazados a la pila y no se pueden capturar de forma segura en el cierre de la máquina de estado asincrónica asignada por el montón.
  • Cambie el tipo de delegado de destino para que coincida con el tipo de valor devuelto de la lambda asincrónica (CS4010). Una expresión lambda asincrónica puede devolver void, Tasko Task<TResult>, y el compilador no puede convertirlas en tipos de delegado arbitrarios que esperan tipos de valor devuelto diferentes.
  • Quite la expresión return de una lambda asincrónica que está asignada a un delegado sin tipo genérico de retorno Task o cambie el tipo del delegado a Func<Task<T>> para que la lambda pueda devolver un valor (CS8031). Un delegado Task no genérico que devuelve representa una operación asincrónica sin resultado, por lo que devolver un valor genera un desajuste de tipos.
  • Quite el [MethodImpl(MethodImplOptions.Synchronized)] atributo de los métodos asincrónicos (CS4015). La Synchronized opción adquiere un bloqueo para toda la ejecución del método, pero un método asincrónico suspende y reanuda potencialmente en subprocesos diferentes, lo que hace que la semántica de bloqueo no se defina.
  • Corrija el tipo personalizado AsyncMethodBuilder para que su Task propiedad devuelva el mismo tipo que el tipo de valor devuelto declarado del método asincrónico (CS8204). El compilador usa la propiedad del generador Task para obtener el objeto de tarea final, por lo que una falta de coincidencia de tipos impide que la máquina de estados funcione correctamente.

Prácticas asincrónicas

  • CS1989: las expresiones lambda asincrónicas no se pueden convertir en árboles de expresión.
  • CS1991: "Type" no puede implementar "event" porque es un evento de Windows Runtime y "event" es un evento de .NET normal.
  • CS1997: Dado que function es un método asincrónico que devuelve un valor, una palabra clave return no debe ir seguida de una expresión de objeto.
  • CS1998: este método asincrónico carece de operadores "await" y se ejecutará sincrónicamente. Considere la posibilidad de usar el operador "await" para esperar llamadas API sin bloqueo o "await Task.Run(...)" para realizar el trabajo enlazado a la CPU en un subproceso en segundo plano.
  • CS4014: dado que no se espera esta llamada, la ejecución del método actual continúa antes de que se complete la llamada. Considere la posibilidad de aplicar el await operador al resultado de la llamada.
  • CS8177: los métodos asincrónicos no pueden tener variables locales de referencia.
  • CS9123: el operador '&' no debe usarse en parámetros ni variables locales en métodos asincrónicos.
  • CS4029: no se puede devolver una expresión de tipo 'void'.
  • CS4030: El atributo security no se puede aplicar a un método asincrónico.
  • CS4031: los métodos asincrónicos no se permiten en un atributo Interface, Class o Structure que tenga el atributo "SecurityCritical" o "SecuritySafeCritical".

Los siguientes elementos explican cómo corregir cada error. Para obtener más información, consulte Programación asincrónica con async y await y el await operador .

  • Agregue el await operador a cada llamada que devuelva Task o Task<TResult>, o descarte explícitamente el resultado con _ = si el comportamiento de disparo y olvido está realmente pensado (CS4014). Sin await, cualquier excepción producida por la operación asincrónica se pierde silenciosamente y el método de llamada continúa ejecutándose antes de que finalice la operación, lo que puede provocar errores sutiles de ordenación y corrección.
  • Quite la return expresión de un método asincrónico cuyo tipo de valor devuelto sea Task (no genérico) o cambie el tipo de valor devuelto a Task<T> cuando el método necesite devolver un valor (CS1997). En un método asincrónico que devuelve Task, el compilador genera el contenedor de tareas; devolver un valor es un error de coincidencia de tipos porque la firma del método no promete ningún resultado.
  • Agregue al menos una await expresión al cuerpo del método o quite el async modificador y devuelva la tarea directamente (CS1998). Un async método sin expresiones await se ejecuta completamente sincrónicamente, lo que agrega sobrecarga innecesaria de la máquina de estado. Si el método encapsula intencionadamente una operación sincrónica, quitar async y devolver la tarea elimina explícitamente esa sobrecarga.
  • Vuelva a escribir la expresión lambda para que no use async cuando se asigna a un tipo de árbol de expresión como Expression<Func<...>> (CS1989). Los árboles de expresión representan código como estructuras de datos que el compilador puede analizar o traducir, pero la máquina de estado compleja que async genera no se puede capturar en un árbol de expresiones.
  • Cambie la implementación del evento para que tanto la declaración de interfaz como la clase de implementación acepten si el evento usa la semántica de Windows Runtime o la semántica de .NET normal (CS1991). Este error se aplica a escenarios de interoperabilidad de Windows Runtime en los que un evento winRT no se puede implementar como un evento de .NET normal o viceversa.
  • Quite el operador address-of (&) de las expresiones que hacen referencia a parámetros o variables locales dentro de métodos asincrónicos (CS9123). La máquina de estado asincrónico podría reubicar variables capturadas en el montón durante la suspensión, lo que invalidaría cualquier puntero obtenido a través de la dirección de .
  • Quite las variables locales por referencia de los métodos asincrónicos o asegúrese de que no abarcan un await límite (CS8177). La máquina de estado asincrónico captura variables locales en cierres asignados por el montón y las referencias a ubicaciones de pila no se pueden conservar de forma segura entre puntos de suspensión. En C# 13 y versiones posteriores, ref locales están permitidos en métodos asincrónicos siempre que no crucen un límite await, y por lo tanto, no se produce este error.
  • Quite la instrucción return que devuelve el resultado de un método que retorna void, o cambie el método llamado para que devuelva un valor (CS4029). No se puede usar return SomeVoidMethod(); porque void no es un tipo que se puede devolver como un valor. Quite la return palabra clave y llame al método como una instrucción independiente o cambie la firma del método llamado para devolver un tipo concreto.
  • Quite atributos de seguridad como [SecurityCritical] o [SecuritySafeCritical] de métodos asincrónicos (CS4030) o quite el async modificador de los métodos de los tipos marcados con estos atributos (CS4031). Las anotaciones de seguridad de acceso de código se aplican al método declarante, pero la máquina de estado asincrónica generada por el compilador se ejecuta en un contexto independiente donde no se pueden aplicar esas anotaciones de seguridad.