without understanding run practices method best await async c# .net async-await naming-conventions naming

understanding - run method async c#



¿El uso del sufijo "Async" en un nombre de método depende de si se usa el modificador ''async''? (7)

¿Cuál es la convención para el sufijo de nombres de métodos con "Async"?

¿El sufijo " async " se debe agregar solo a un método que se declara con el modificador async ?

public async Task<bool> ConnectAsync()

¿O es suficiente que el método simplemente devuelva Task<T> o Task ?

public Task<bool> ConnectAsync()


¿Cuál es la convención para los nombres de método de sufijo con "Async".

El patrón asíncrono basado en tareas (TAP) dicta que los métodos siempre deben devolver una Task<T> (o Task ) y ser nombrados con un sufijo asíncrono ; Esto es independiente del uso de async . Tanto Task<bool> Connect() como async Task<bool> Connect() se compilarán y ejecutarán bien, pero no seguirás la convención de nomenclatura de TAP.

¿Debe el método contener el modificador async , o es suficiente para que simplemente devuelva la tarea?

Si el cuerpo del método (independientemente del tipo o nombre de retorno) incluye await , debe usar async ; y el compilador le dirá "El operador ''await'' solo se puede usar dentro de un método asíncrono ...". Devolver la Task<T> o la Task no es "suficiente" para evitar el uso de async . Ver async (Referencia de C #) para más detalles.

Es decir, cuáles de estas firmas son correctas:

Tanto la Task<bool> ConnectAsync() async Task<bool> ConnectAsync() como la Task<bool> ConnectAsync() siguen correctamente las convenciones de TAP. Siempre puede usar la palabra clave async , pero recibirá una advertencia del compilador "Este método asíncrono carece de operadores de" espera "y se ejecutará de forma síncrona ..." si el cuerpo no usa await .


¿O es suficiente que solo devuelva la tarea?

Ese. La palabra clave async no es el verdadero problema aquí. Si implementa la asincronía sin usar la palabra clave async el método sigue siendo " async ", en el sentido general.


Construyo muchos servicios de API y otras aplicaciones que llaman a otros sistemas donde la mayoría de mi código se ejecuta de forma asíncrona.

Mi propia regla de oro que estoy siguiendo es:

Si hay métodos asíncronos y no asíncronos que devuelven lo mismo, sufijo el de asíncrono con asíncrono. De otra forma no.

Ejemplos:

Sólo un método:

public async Task<User> GetUser() { [...] }

Mismo método con dos firmas:

public User GetUser() { [...] } public async Task<User> GetUserAsync() { [...] }

Esto tiene sentido ya que son los mismos datos que se devuelven, pero lo único que difiere es la forma de devolver los datos , no los datos en sí.

También creo que estas convenciones de nomenclatura existen debido a la necesidad de introducir métodos asíncronos y mantener la compatibilidad hacia atrás.

Sostengo que el nuevo código no debería usar el sufijo Async. Es tan obvio como el tipo de cadena de retorno o Int, como se mencionó anteriormente en este hilo.


Creo que la verdad es ambigua incluso de la documentación de Microsoft:

En Visual Studio 2012 y .NET Framework 4.5, cualquier método que se atribuya con la palabra clave async ( Async en Visual Basic) se considera un método asíncrono, y los compiladores C # y Visual Basic realizan las transformaciones necesarias para implementar el método de forma asíncrona utilizando GRIFO. Un método asíncrono debe devolver un objeto Task o Task<TResult> .

http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx

Eso no está bien ya. Cualquier método con async es asíncrono y luego dice que debe devolver una Task o Task<T> , lo que no es correcto para los métodos en la parte superior de una pila de llamadas, Button_Click, por ejemplo, o async void .

Por supuesto, tienes que considerar cuál es el punto de la convención?

Se podría decir que la convención del sufijo Async es comunicar al usuario de la API que el método está en espera. Para que un método se pueda esperar, debe devolver Task para un vacío, o Task<T> para un método de retorno de valor, lo que significa que solo el último puede incluir el sufijo Async .

O podría decir que la convención del sufijo Async es comunicar que el método puede retornar de inmediato, renunciar al hilo actual para realizar otro trabajo y posiblemente generar carreras.

Esta cita del documento de Microsoft dice:

Por convención, agregue "Async" a los nombres de los métodos que tienen un modificador Async o async.

http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

Lo que ni siquiera menciona que sus propios métodos asíncronos que devuelven la Task necesitan el sufijo Async , que creo que todos estamos de acuerdo en que sí.

Así que la respuesta a esta pregunta podría ser: ambas. En ambos casos, debe agregar Async a los métodos con palabras clave async y que devuelven Task o Task<T> .

Le voy a pedir a Stephen Toub que aclare la situación.

Actualizar

Así que lo hice. Y aquí está lo que nuestro buen hombre escribió:

Si un método público devuelve una Tarea y es de naturaleza asíncrona (a diferencia de un método que se sabe que siempre se ejecuta de forma síncrona pero aún así devuelve una Tarea por alguna razón), debe tener un sufijo "Asíncrono". Esa es la pauta. El objetivo principal aquí con la denominación es hacer que sea muy obvio para un consumidor de la funcionalidad que el método que se invoca probablemente no complete todo su trabajo de forma sincrónica; Por supuesto, también ayuda con el caso en el que la funcionalidad se expone con métodos síncronos y asíncronos, de modo que se necesita una diferencia de nombre para distinguirlos. La forma en que el método logra su implementación asíncrona no es importante para la denominación: si async / await se utiliza para recopilar la ayuda del compilador, o si los tipos y métodos de System.Threading.Tasks se usan directamente (por ejemplo, TaskCompletionSource) realmente no importa, como eso no afecta la firma del método en lo que concierne a un consumidor del método.

Por supuesto, siempre hay excepciones a una directriz. El más notable en el caso de la asignación de nombres sería en los casos en que la razón de ser de un tipo completo es proporcionar una funcionalidad centrada en async, en cuyo caso tener Async en cada método sería excesivo, por ejemplo, los métodos en la propia Tarea que producen otras Tareas. .

En cuanto a los métodos asíncronos de retorno de vacío, no es deseable tenerlos en el área de superficie pública, ya que la persona que llama no tiene una buena forma de saber cuándo se ha completado el trabajo asíncrono. Sin embargo, si debe exponer públicamente un método asíncrono de devolución de vacíos, es probable que desee tener un nombre que indique que se está iniciando el trabajo asíncrono, y podría usar el sufijo "Asíncrono" aquí si tuviera sentido. Teniendo en cuenta lo raro que debería ser este caso, diría que es realmente un tipo de decisión caso por caso.

Espero que eso ayude, Steve

La guía sucinta de la oración inicial de Stephen es bastante clara. Excluye el async void porque es inusual querer crear una API pública con un diseño de este tipo, ya que la forma correcta de implementar un vacío asíncrono es devolver una instancia de Task simple y dejar que el compilador haga su magia. Sin embargo, si usted quería un public async void , entonces se recomienda agregar Async . Otros métodos async void parte superior de la pila, como los controladores de eventos, generalmente no son públicos y no importan / califican.

Para mí, me dice que si me pregunto sobre el sufijo de Async en un async void , probablemente debería convertirlo en una async Task para que las personas que llaman puedan esperar, luego agregar Async .


Dado que la Task y la Task<T> son tipos que se pueden esperar, representan una operación asíncrona. O al menos deberían representar.

Debe agregar el sufijo Async a un método que, en algunos casos (no necesariamente todos), no devuelve un valor, sino que devuelve un contenedor alrededor de una operación en curso. Ese envoltorio suele ser una Task , pero en Windows RT puede ser IAsyncInfo . Siga sus instintos y recuerde que si un usuario de su código ve la función Async , sabrá que la invocación de ese método está desacoplada del resultado de ese método y que deben actuar en consecuencia.

Tenga en cuenta que existen métodos como Task.Delay y Task.WhenAll que devuelven la Task y aún no tienen el sufijo Async .

También tenga en cuenta que existen métodos de async void que representan el método asíncrono de incendio y de olvido , y debe tener en cuenta que el método está construido de tal manera.


En la programación asíncrona con async y await (C #) , Microsoft ofrece la siguiente guía:

Convenio de denominación

Por convención, agregue "Async" a los nombres de los métodos que tienen un modificador async .

Puede ignorar la convención donde un evento, clase base o contrato de interfaz sugiere un nombre diferente. Por ejemplo, no debe cambiar el nombre de los controladores de eventos comunes, como Button1_Click .

Encuentro esta guía incompleta e insatisfactoria. ¿Significa esto que en ausencia del modificador async , este método debería llamarse Connect lugar de ConnectAsync ?

public Task<bool> ConnectAsync() { return ConnectAsyncInternal(); }

No lo creo. Como se indica en la respuesta concisa de Servy y la respuesta más detallada de @Luke Puplett , creo que es apropiado y, de hecho, se esperaba que este método se llamara ConnectAsync (porque devuelve algo que se puede esperar). Como apoyo adicional de esto, @John Skeet en esta respuesta a otra pregunta agrega Async al nombre del método, independientemente de la presencia del modificador async .

Finalmente, en otra pregunta , considere este comentario de @Damien_The_Unbeliever :

async/await son detalles de implementación de sus métodos. No importa ni una sola nota si su método se ha declarado async Task Method() o solo Task Method() , en lo que respecta a sus interlocutores . (De hecho, tiene la libertad de cambiar entre estos dos en un momento posterior sin que se considere un cambio importante).

De eso, deduzco que es la naturaleza asíncrona del método lo que determina cómo debe ser nombrado. El usuario del método ni siquiera sabrá si el modificador async se utiliza en su implementación (sin el código fuente de C # o CIL).


Yo diría que debería usar el sufijo Async si devuelve una Tarea independientemente de si el método se declara con el modificador async .

La razón detrás de esto es que el nombre está declarado en la interfaz. La interfaz declara el tipo de retorno que es una Task . Luego hay dos implementaciones de esa interfaz, una implementación la implementa utilizando el modificador async , la otra no.

public interface IFoo { Task FooAsync(); } public class FooA : IFoo { public Task FooAsync() { /* ... */ } } public class FooB : IFoo { public async Task FooAsync() { /* ... */ } }