Agradecemos tu ayuda para difundir nuestros posts acerca de las ciencias de la computación.
Solución:
los asincrónico la palabra clave es simplemente un detalle de implementación de un método; no forma parte de la firma del método. Si la implementación o anulación de un método en particular no tiene nada que esperar, simplemente omita el asincrónico palabra clave y devolver una tarea completada usando Task.FromResult
public Task Foo() // public async Task Foo()
//
Baz(); // Baz();
return Task.FromResult("Hello"); // return "Hello";
//
Si su método devuelve Task en lugar de TaskTask.FromResult(0)
parece ser una opción popular:
public Task Bar() // public async Task Bar()
//
Baz(); // Baz();
return Task.FromResult(0); //
//
O, a partir de .NET Framework 4.6, puede devolver Task.CompletedTask:
public Task Bar() // public async Task Bar()
//
Baz(); // Baz();
return Task.CompletedTask; //
//
Es perfectamente razonable que algunas operaciones “asincrónicas” se completen sincrónicamente, pero aún así se ajusten al modelo de llamadas asincrónicas por el polimorfismo.
Un ejemplo real de esto es con las API de E / S del SO. Las llamadas asincrónicas y superpuestas en algunos dispositivos siempre se completan en línea (la escritura en una tubería implementada mediante memoria compartida, por ejemplo). Pero implementan la misma interfaz que las operaciones de varias partes que continúan en segundo plano.
Puede que sea demasiado tarde, pero podría ser útil una investigación:
Hay una estructura interna del código compilado (ILLINOIS):
public static async Task GetTestData()
return 12;
se convierte en en IL:
.method private hidebysig static class [mscorlib]System.Threading.Tasks.Task`1
GetTestData() cil managed
.custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = ( 01 00 28 55 73 61 67 65 4C 69 62 72 61 72 79 2E // ..(UsageLibrary.
53 74 61 72 74 54 79 70 65 2B 3C 47 65 74 54 65 // StartType+d__1..
.custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = ( 01 00 00 00 )
// Code size 52 (0x34)
.maxstack 2
.locals init ([0] class UsageLibrary.StartType/'d__1' V_0,
[1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 V_1)
IL_0000: newobj instance void UsageLibrary.StartType/'d__1'::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create()
IL_000c: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 UsageLibrary.StartType/'d__1'::'<>t__builder'
IL_0011: ldloc.0
IL_0012: ldc.i4.m1
IL_0013: stfld int32 UsageLibrary.StartType/'d__1'::'<>1__state'
IL_0018: ldloc.0
IL_0019: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 UsageLibrary.StartType/'d__1'::'<>t__builder'
IL_001e: stloc.1
IL_001f: ldloca.s V_1
IL_0021: ldloca.s V_0
IL_0023: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Startd__1'>(!!0&)
IL_0028: ldloc.0
IL_0029: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 UsageLibrary.StartType/'d__1'::'<>t__builder'
IL_002e: call instance class [mscorlib]System.Threading.Tasks.Task`1 valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task()
IL_0033: ret
// end of method StartType::GetTestData
Y sin método asincrónico y de tarea:
public static int GetTestData()
return 12;
se convierte en:
.method private hidebysig static int32 GetTestData() cil managed
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] int32 V_0)
IL_0000: nop
IL_0001: ldc.i4.s 12
IL_0003: stloc.0
IL_0004: br.s IL_0006
IL_0006: ldloc.0
IL_0007: ret
// end of method StartType::GetTestData
Como puede ver, la gran diferencia entre estos métodos. Si no usa el método await inside async y no le importa usar el método async (por ejemplo, una llamada a la API o un controlador de eventos), la buena idea lo convertirá en un método de sincronización normal (ahorra el rendimiento de su aplicación).
Actualizado:
También hay información adicional de microsoft docs:
Los métodos asíncronos deben tener una palabra clave de espera en su cuerpo o nunca cederán. Es importante tener esto en cuenta. Si await no se usa en el cuerpo de un método asincrónico, el compilador de C # generará una advertencia, pero el código se compilará y se ejecutará como si fuera un método normal. Tenga en cuenta que esto también sería increíblemente ineficiente, ya que la máquina de estado generada por el compilador de C # para el método asíncrono no lograría nada.
Tienes la posibilidad difundir este enunciado si lograste el éxito.