我应该担心"这种异步方法缺乏'等待'运算符并将同步运行"警告

dan*_*710 65 .net c# asynchronous task async-await

我有一个接口,它暴露了一些异步方法.更具体地说,它定义了返回Task或Task <T>的方法.我正在使用async/await关键字.

我正在实现这个接口.但是,在其中一些方法中,此实现没有任何东西需要等待.出于这个原因,我得到编译器警告"这个异步方法缺少'等待'运算符,并将同步运行......"

我理解为什么我会收到错误,但我想知道在这种情况下我是否应该对它们采取任何措施.忽略编译器警告感觉不对.

我知道我可以通过等待Task.Run来修复它,但对于只做一些廉价操作的方法来说感觉不对.它听起来也会为执行添加不必要的开销,但后来我也不确定是否已经存在,因为async关键字存在.

我应该忽略这些警告还是有办法解决这个问题,我没有看到?

Mic*_*Liu 112

异步关键字仅仅是一个方法的实施方案的细节; 它不是方法签名的一部分.如果一个特定的方法实现或覆盖没有任何东西可以等待,那么只需省略async关键字并使用Task.FromResult <TResult>返回已完成的任务:

public Task<string> Foo()               //    public async Task<string> Foo()
{                                       //    {
    Baz();                              //        Baz();
    return Task.FromResult("Hello");    //        return "Hello";
}                                       //    }
Run Code Online (Sandbox Code Playgroud)

如果您的方法返回Task而不是Task <TResult>,那么您可以返回任何类型和值的已完成任务.Task.FromResult(0)似乎是一个受欢迎的选择:

public Task Bar()                       //    public async Task Bar()
{                                       //    {
    Baz();                              //        Baz();
    return Task.FromResult(0);          //
}                                       //    }
Run Code Online (Sandbox Code Playgroud)

或者,从.NET Framework 4.6开始,您可以返回Task.CompletedTask:

public Task Bar()                       //    public async Task Bar()
{                                       //    {
    Baz();                              //        Baz();
    return Task.CompletedTask;          //
}                                       //    }
Run Code Online (Sandbox Code Playgroud)

  • @Sushi271:不,在非`async` 方法中,您**返回** `Task.FromResult(0)` 而不是等待它。 (2认同)

Ben*_*igt 13

一些"异步"操作同步完成,但为了多态而仍然符合异步调用模型,这是完全合理的.

一个真实的例子是OS I/O API.某些设备上的异步和重叠调用始终完成内联(例如,写入使用共享内存实现的管道).但它们实现了与多部分操作相同的界面,这些操作在后台继续进行.


Ole*_*nko 7

可能为时已晚,但可能是有用的调查:

编译代码( IL )的内部结构如下:

public static async Task<int> GetTestData()
{
    return 12;
}
Run Code Online (Sandbox Code Playgroud)

在IL中它变成:

.method private hidebysig static class [mscorlib]System.Threading.Tasks.Task`1<int32> 
        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+<GetTe
                                                                                                                                     73 74 44 61 74 61 3E 64 5F 5F 31 00 00 )          // stData>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/'<GetTestData>d__1' V_0,
           [1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> V_1)
  IL_0000:  newobj     instance void UsageLibrary.StartType/'<GetTestData>d__1'::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  call       valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Create()
  IL_000c:  stfld      valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> UsageLibrary.StartType/'<GetTestData>d__1'::'<>t__builder'
  IL_0011:  ldloc.0
  IL_0012:  ldc.i4.m1
  IL_0013:  stfld      int32 UsageLibrary.StartType/'<GetTestData>d__1'::'<>1__state'
  IL_0018:  ldloc.0
  IL_0019:  ldfld      valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> UsageLibrary.StartType/'<GetTestData>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<int32>::Start<class UsageLibrary.StartType/'<GetTestData>d__1'>(!!0&)
  IL_0028:  ldloc.0
  IL_0029:  ldflda     valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> UsageLibrary.StartType/'<GetTestData>d__1'::'<>t__builder'
  IL_002e:  call       instance class [mscorlib]System.Threading.Tasks.Task`1<!0> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::get_Task()
  IL_0033:  ret
} // end of method StartType::GetTestData
Run Code Online (Sandbox Code Playgroud)

并且没有异步和任务方法:

 public static int GetTestData()
 {
      return 12;
 }
Run Code Online (Sandbox Code Playgroud)

变成:

.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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这些方法之间存在巨大差异。如果您不在异步方法中使用await并且不关心异步方法的使用(例如API调用或事件处理程序),那么最好将其转换为普通的同步方法(它可以节省应用程序性能)。

更新:

微软文档还提供了其他信息:

异步方法需要在其主体中有一个await关键字,否则它们将永远不会屈服!记住这一点很重要。如果异步方法的主体中未使用await,C#编译器将生成警告,但代码将像普通方法一样编译和运行。请注意,这也会非常低效,因为 C# 编译器为异步方法生成的状态机不会完成任何事情。

  • 此外,您对使用“async/await”的最终结论过于简单化,因为您是基于受 CPU 限制的单个操作的不切实际的示例。正确使用“任务”时,由于并发任务(即并行)以及更好的线程管理和使用,可以提高应用程序性能和响应能力 (3认同)
  • 返回“int”的方法(如您的情况)和返回“Task”的方法(如OP所讨论的)之间存在差异。**再次**阅读_他_的帖子和接受的答案,而不是个人认为。您的回答在这种情况下没有帮助。您甚至懒得去展示内部有或没有“await”的方法之间的区别。现在,如果你做到了,那将是_非常好_值得投票 (3认同)

Ian*_*emp 7

仅当您实际调用所涉及的方法,并且仅当性能是一个问题时。

这可以通过编写包含以下 4 个方法的程序,然后将它们反编译为IL来演示(请注意,所提供的 IL 可能会在运行时版本之间发生变化;以下来自 .NET Core 3.1):

int FullySync() => 42;

Task<int> TaskSync() => Task.FromResult(42);

// CS1998
async Task<int> NotActuallyAsync() => 42;

async Task<int> FullyAsync() => await Task.Run(() => 42);
Run Code Online (Sandbox Code Playgroud)

前两个结果会产生非常短的方法体,其中包含您所期望的内容:

.method private hidebysig 
    instance int32 FullySync () cil managed 
{
    // Method begins at RVA 0x205e
    // Code size 3 (0x3)
    .maxstack 8

    // return 42;
    IL_0000: ldc.i4.s 42
    IL_0002: ret
} // end of method Program::FullySync

.method private hidebysig 
    instance class [System.Runtime]System.Threading.Tasks.Task`1<int32> TaskSync () cil managed 
{
    // Method begins at RVA 0x2062
    // Code size 8 (0x8)
    .maxstack 8

    // return Task.FromResult(42);
    IL_0000: ldc.i4.s 42
    IL_0002: call class [System.Runtime]System.Threading.Tasks.Task`1<!!0> [System.Runtime]System.Threading.Tasks.Task::FromResult<int32>(!!0)
    IL_0007: ret
} // end of method Program::TaskSync
Run Code Online (Sandbox Code Playgroud)

async但是最后两个关键字的存在会导致编译器为这些方法生成异步状态机

.method private hidebysig 
    instance class [System.Runtime]System.Threading.Tasks.Task`1<int32> NotActuallyAsync () cil managed 
{
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [System.Runtime]System.Type) = (
        01 00 29 43 53 31 39 39 38 54 65 73 74 2e 50 72
        6f 67 72 61 6d 2b 3c 4e 6f 74 41 63 74 75 61 6c
        6c 79 41 73 79 6e 63 3e 64 5f 5f 33 00 00
    )
    .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = (
        01 00 00 00
    )
    // Method begins at RVA 0x206c
    // Code size 56 (0x38)
    .maxstack 2
    .locals init (
        [0] class CS1998Test.Program/'<NotActuallyAsync>d__3'
    )

    IL_0000: newobj instance void CS1998Test.Program/'<NotActuallyAsync>d__3'::.ctor()
    IL_0005: stloc.0
    IL_0006: ldloc.0
    IL_0007: call valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Create()
    IL_000c: stfld valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>t__builder'
    IL_0011: ldloc.0
    IL_0012: ldarg.0
    IL_0013: stfld class CS1998Test.Program CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>4__this'
    IL_0018: ldloc.0
    IL_0019: ldc.i4.m1
    IL_001a: stfld int32 CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>1__state'
    IL_001f: ldloc.0
    IL_0020: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>t__builder'
    IL_0025: ldloca.s 0
    IL_0027: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Start<class CS1998Test.Program/'<NotActuallyAsync>d__3'>(!!0&)
    IL_002c: ldloc.0
    IL_002d: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>t__builder'
    IL_0032: call instance class [System.Runtime]System.Threading.Tasks.Task`1<!0> valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::get_Task()
    IL_0037: ret
} // end of method Program::NotActuallyAsync

.class nested private auto ansi sealed beforefieldinit '<NotActuallyAsync>d__3'
    extends [System.Runtime]System.Object
    implements [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine
{
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    // Fields
    .field public int32 '<>1__state'
    .field public valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> '<>t__builder'
    .field public class CS1998Test.Program '<>4__this'

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x20fd
        // Code size 8 (0x8)
        .maxstack 8

        // {
        IL_0000: ldarg.0
        // (no C# code)
        IL_0001: call instance void [System.Runtime]System.Object::.ctor()
        // }
        IL_0006: nop
        IL_0007: ret
    } // end of method '<NotActuallyAsync>d__3'::.ctor

    .method private final hidebysig newslot virtual 
        instance void MoveNext () cil managed 
    {
        .override method instance void [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext()
        // Method begins at RVA 0x2108
        // Code size 58 (0x3a)
        .maxstack 2
        .locals init (
            [0] int32,
            [1] int32,
            [2] class [System.Runtime]System.Exception
        )

        // int num = <>1__state;
        IL_0000: ldarg.0
        IL_0001: ldfld int32 CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>1__state'
        IL_0006: stloc.0
        .try
        {
            // result = 42;
            IL_0007: ldc.i4.s 42
            IL_0009: stloc.1
            // }
            IL_000a: leave.s IL_0024
        } // end .try
        catch [System.Runtime]System.Exception
        {
            // catch (Exception exception)
            IL_000c: stloc.2
            // <>1__state = -2;
            IL_000d: ldarg.0
            IL_000e: ldc.i4.s -2
            IL_0010: stfld int32 CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>1__state'
            // <>t__builder.SetException(exception);
            IL_0015: ldarg.0
            IL_0016: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>t__builder'
            IL_001b: ldloc.2
            IL_001c: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetException(class [System.Runtime]System.Exception)
            // return;
            IL_0021: nop
            IL_0022: leave.s IL_0039
        } // end handler

        // <>1__state = -2;
        IL_0024: ldarg.0
        IL_0025: ldc.i4.s -2
        IL_0027: stfld int32 CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>1__state'
        // <>t__builder.SetResult(result);
        IL_002c: ldarg.0
        IL_002d: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<NotActuallyAsync>d__3'::'<>t__builder'
        IL_0032: ldloc.1
        IL_0033: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetResult(!0)
        // }
        IL_0038: nop

        IL_0039: ret
    } // end of method '<NotActuallyAsync>d__3'::MoveNext

    .method private final hidebysig newslot virtual 
        instance void SetStateMachine (
            class [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine
        ) cil managed 
    {
        .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = (
            01 00 00 00
        )
        .override method instance void [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine)
        // Method begins at RVA 0x2160
        // Code size 1 (0x1)
        .maxstack 8

        // }
        IL_0000: ret
    } // end of method '<NotActuallyAsync>d__3'::SetStateMachine

} // end of class <NotActuallyAsync>d__3

.method private hidebysig 
    instance class [System.Runtime]System.Threading.Tasks.Task`1<int32> FullyAsync () cil managed 
{
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [System.Runtime]System.Type) = (
        01 00 23 43 53 31 39 39 38 54 65 73 74 2e 50 72
        6f 67 72 61 6d 2b 3c 46 75 6c 6c 79 41 73 79 6e
        63 3e 64 5f 5f 34 00 00
    )
    .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = (
        01 00 00 00
    )
    // Method begins at RVA 0x20b0
    // Code size 56 (0x38)
    .maxstack 2
    .locals init (
        [0] class CS1998Test.Program/'<FullyAsync>d__4'
    )

    IL_0000: newobj instance void CS1998Test.Program/'<FullyAsync>d__4'::.ctor()
    IL_0005: stloc.0
    IL_0006: ldloc.0
    IL_0007: call valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<!0> valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Create()
    IL_000c: stfld valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>t__builder'
    IL_0011: ldloc.0
    IL_0012: ldarg.0
    IL_0013: stfld class CS1998Test.Program CS1998Test.Program/'<FullyAsync>d__4'::'<>4__this'
    IL_0018: ldloc.0
    IL_0019: ldc.i4.m1
    IL_001a: stfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>1__state'
    IL_001f: ldloc.0
    IL_0020: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>t__builder'
    IL_0025: ldloca.s 0
    IL_0027: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Start<class CS1998Test.Program/'<FullyAsync>d__4'>(!!0&)
    IL_002c: ldloc.0
    IL_002d: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>t__builder'
    IL_0032: call instance class [System.Runtime]System.Threading.Tasks.Task`1<!0> valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::get_Task()
    IL_0037: ret
} // end of method Program::FullyAsync

.class nested private auto ansi sealed beforefieldinit '<FullyAsync>d__4'
    extends [System.Runtime]System.Object
    implements [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine
{
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    // Fields
    .field public int32 '<>1__state'
    .field public valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> '<>t__builder'
    .field public class CS1998Test.Program '<>4__this'
    .field private int32 '<>s__1'
    .field private valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32> '<>u__1'

    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x217b
        // Code size 8 (0x8)
        .maxstack 8

        // {
        IL_0000: ldarg.0
        // (no C# code)
        IL_0001: call instance void [System.Runtime]System.Object::.ctor()
        // }
        IL_0006: nop
        IL_0007: ret
    } // end of method '<FullyAsync>d__4'::.ctor

    .method private final hidebysig newslot virtual 
        instance void MoveNext () cil managed 
    {
        .override method instance void [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext()
        // Method begins at RVA 0x2184
        // Code size 199 (0xc7)
        .maxstack 3
        .locals init (
            [0] int32,
            [1] int32,
            [2] valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32>,
            [3] class CS1998Test.Program/'<FullyAsync>d__4',
            [4] class [System.Runtime]System.Exception
        )

        // int num = <>1__state;
        IL_0000: ldarg.0
        IL_0001: ldfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>1__state'
        IL_0006: stloc.0
        .try
        {
            // if (num != 0)
            IL_0007: ldloc.0
            IL_0008: brfalse.s IL_000c

            // (no C# code)
            IL_000a: br.s IL_000e

            // awaiter = Task.Run(() => 42).GetAwaiter();
            IL_000c: br.s IL_0065

            IL_000e: ldsfld class [System.Runtime]System.Func`1<int32> CS1998Test.Program/'<>c'::'<>9__4_0'
            IL_0013: dup
            IL_0014: brtrue.s IL_002d

            // (no C# code)
            IL_0016: pop
            // if (!awaiter.IsCompleted)
            IL_0017: ldsfld class CS1998Test.Program/'<>c' CS1998Test.Program/'<>c'::'<>9'
            IL_001c: ldftn instance int32 CS1998Test.Program/'<>c'::'<FullyAsync>b__4_0'()
            IL_0022: newobj instance void class [System.Runtime]System.Func`1<int32>::.ctor(object, native int)
            IL_0027: dup
            IL_0028: stsfld class [System.Runtime]System.Func`1<int32> CS1998Test.Program/'<>c'::'<>9__4_0'

            IL_002d: call class [System.Runtime]System.Threading.Tasks.Task`1<!!0> [System.Runtime]System.Threading.Tasks.Task::Run<int32>(class [System.Runtime]System.Func`1<!!0>)
            IL_0032: callvirt instance valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<!0> class [System.Runtime]System.Threading.Tasks.Task`1<int32>::GetAwaiter()
            IL_0037: stloc.2
            IL_0038: ldloca.s 2
            IL_003a: call instance bool valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32>::get_IsCompleted()
            IL_003f: brtrue.s IL_0081

            // num = (<>1__state = 0);
            IL_0041: ldarg.0
            IL_0042: ldc.i4.0
            IL_0043: dup
            IL_0044: stloc.0
            IL_0045: stfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>1__state'
            // <>u__1 = awaiter;
            IL_004a: ldarg.0
            IL_004b: ldloc.2
            IL_004c: stfld valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>u__1'
            // <FullyAsync>d__4 stateMachine = this;
            IL_0051: ldarg.0
            IL_0052: stloc.3
            // <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
            IL_0053: ldarg.0
            IL_0054: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>t__builder'
            IL_0059: ldloca.s 2
            IL_005b: ldloca.s 3
            IL_005d: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::AwaitUnsafeOnCompleted<valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32>, class CS1998Test.Program/'<FullyAsync>d__4'>(!!0&, !!1&)
            // return;
            IL_0062: nop
            IL_0063: leave.s IL_00c6

            // awaiter = <>u__1;
            IL_0065: ldarg.0
            IL_0066: ldfld valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>u__1'
            IL_006b: stloc.2
            // <>u__1 = default(TaskAwaiter<int>);
            IL_006c: ldarg.0
            IL_006d: ldflda valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>u__1'
            IL_0072: initobj valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32>
            // num = (<>1__state = -1);
            IL_0078: ldarg.0
            IL_0079: ldc.i4.m1
            IL_007a: dup
            IL_007b: stloc.0
            IL_007c: stfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>1__state'

            // <>s__1 = awaiter.GetResult();
            IL_0081: ldarg.0
            IL_0082: ldloca.s 2
            IL_0084: call instance !0 valuetype [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter`1<int32>::GetResult()
            IL_0089: stfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>s__1'
            // result = <>s__1;
            IL_008e: ldarg.0
            IL_008f: ldfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>s__1'
            IL_0094: stloc.1
            // }
            IL_0095: leave.s IL_00b1
        } // end .try
        catch [System.Runtime]System.Exception
        {
            // catch (Exception exception)
            IL_0097: stloc.s 4
            // <>1__state = -2;
            IL_0099: ldarg.0
            IL_009a: ldc.i4.s -2
            IL_009c: stfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>1__state'
            // <>t__builder.SetException(exception);
            IL_00a1: ldarg.0
            IL_00a2: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>t__builder'
            IL_00a7: ldloc.s 4
            IL_00a9: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetException(class [System.Runtime]System.Exception)
            // return;
            IL_00ae: nop
            IL_00af: leave.s IL_00c6
        } // end handler

        // <>1__state = -2;
        IL_00b1: ldarg.0
        IL_00b2: ldc.i4.s -2
        IL_00b4: stfld int32 CS1998Test.Program/'<FullyAsync>d__4'::'<>1__state'
        // <>t__builder.SetResult(result);
        IL_00b9: ldarg.0
        IL_00ba: ldflda valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> CS1998Test.Program/'<FullyAsync>d__4'::'<>t__builder'
        IL_00bf: ldloc.1
        IL_00c0: call instance void valuetype [System.Threading.Tasks]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::SetResult(!0)
        // }
        IL_00c5: nop

        IL_00c6: ret
    } // end of method '<FullyAsync>d__4'::MoveNext

    .method private final hidebysig newslot virtual 
        instance void SetStateMachine (
            class [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine stateMachine
        ) cil managed 
    {
        .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = (
            01 00 00 00
        )
        .override method instance void [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine(class [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine)
        // Method begins at RVA 0x226


Dan*_*don 6

Michael Liu很好地回答了您有关如何避免警告的问题:通过返回Task.FromResult。

我将回答您问题的“我应该担心警告”部分。

答案是肯定的!

这样做的原因是,当您调用Task在没有await操作员的情况下在异步方法内部返回的方法时,经常会出现警告。我只是修复了发生的并发错误,因为我在不等待上一个操作的情况下在Entity Framework中调用了一个操作。

如果您可以精心编写代码以避免编译器警告,那么当出现警告时,它将像疼痛的拇指一样突出。我本可以避免几个小时的调试。

  • 这个答案是错误的。原因如下:方法内的一个地方至少可以有一个 `await` (不会有 CS1998),但这并不意味着不会有其他缺乏同步的 asnyc 方法调用(使用 `await` ` 或任何其他)。现在,如果有人想知道如何确保您不会意外错过同步,那么只需确保您没有忽略另一个警告 - CS4014。我什至建议威胁那个错误。 (7认同)