没有EndInvoke的C#异步调用?

Jue*_*gen 10 c# delegates action asynchronous

以下面的课程为例.

public class A
{
   // ...
   void Foo(S myStruct){...}
}

public class B
{
   public A test;
   // ...
   void Bar()
   {
      S myStruct = new S();
      test.Foo(myStruct);
   }
}
Run Code Online (Sandbox Code Playgroud)

现在,我希望方法调用test.Foo(myStruct)是一个异步调用('fire-and-forget').条形方法需要尽快返回.代理,BeginInvoke,EndInvoke,ThreadPool等文档不能帮助我找到解决方案.

这是有效的解决方案吗?

     // Is using the `EndInvoke` method as the callback delegate valid?
     foo.BeginInvoke(myStruct, foo.EndInvoke, null);
Run Code Online (Sandbox Code Playgroud)

Jon*_*son 12

你不需要打电话EndInvoke; 不称它仅仅意味着:

  • 您没有从方法中获得返回值.
  • 在方法执行期间抛出的任何异常都将消失.

听起来你想要"发射并忘记",所以最简单的方法是使用匿名委托,例如:

var del = new Action(foo.Bar);
del.BeginInvoke(iar =>
{
   try
   {
      del.EndInvoke(iar);
   }
   catch (Exception ex)
   {
      // Log the message?
   }
}, null);
Run Code Online (Sandbox Code Playgroud)

这是执行此代码时发生的情况:

  1. 为委托分配(简单地)新线程.
  2. 该线程被赋予委托del和匿名委托(iar => ...).
  3. 线程执行del.
  4. 当它完成执行(或发生异常)时,将存储结果或异常并执行匿名委托.
  5. 在匿名委托内部,当EndInvoke调用when时,返回该方法的结果,或者抛出异常(如果发生了一个异常).

请注意,上面的示例与以下示例非常不同:

// This is pointless and is still, essentially, synchronous.
del.EndInvoke(del.BeginInvoke(null, null));
Run Code Online (Sandbox Code Playgroud)

编辑:你应该总是打电话End*.我从来没有找到一个不调用它会出现问题的场景,但这是一个实现细节,并且依赖于未记录的行为.

最后,如果抛出异常,您的解决方案将使进程崩溃,如果您不关心异常(del.BeginInvoke(myStruct, null, null);),则可以简单地将null作为委托传递.因此,作为最后一个例子,您正在寻找的可能是:

public class A
{
    // ...
    void Foo(S myStruct){...}
    void FooAsync(S myStruct)
    {
        var del = new Action<S>(Foo);
        del.BeginInvoke(myStruct, SuppressException, del);
    }

    static void SuppressException(IAsyncResult ar)
    {
        try
        {
            ((Action<S>)ar.AsyncState).EndInvoke(ar);
        }
        catch
        {
            // TODO: Log
        }
    }
}
Run Code Online (Sandbox Code Playgroud)