未实现/支持/无效操作异步方法

时间:2017-05-04 20:52:20

标签: c# async-await

将async方法标记为未实现/不支持或无效操作的正确方法是什么。为简单起见,我在示例中仅使用NotImplementedException,但此问题也适用于NotSupportedExceptionInvalidOperationException

以同步方式,可以简单地抛出异常:

public override void X() {
    throw new NotImplementedException();
}

在异步世界中,这段代码的等价物是什么?

/* 1 */ public override Task XAsync() {
    throw new NotImplementedException();
}

/* 2 */ public override Task XAsync() {
    return Task.FromException(new NotImplementedException());
}

这些方法的并发症有哪些?有没有更好的方法?

为了避免“Nah,你不需要一个方法在这里异步”/“它不是异步”我会说该方法实现了一些接口或抽象类。

我不考虑的一些方法:

/* 3 */ public async override Task XAsync() { // here is an CS1998 warning 
    throw new NotImplementedException();
}

编译器would just generate the useless state machine,在语义上等同于2

/* 4 */ public async override Task XAsync() {
    await Task.Yield();
    throw new NotImplementedException();
}

这是the same为3,但是在Task.Yeild()上添加等待;

3 个答案:

答案 0 :(得分:5)

我要站出来说“没关系。”

Boneheaded exceptions可以直接抛出(throw)或放在返回的任务(Task.FromException)上。由于它们是愚蠢的例外,它们不应该被捕获,所以抛出它们并不重要。

答案 1 :(得分:3)

当调用返回FlxG.worldBounds.set(?X:Float = 0, ?Y:Float = 0, ?Width:Float = 0, ?Height:Float = 0)的方法时,它的某些部分会同步执行(即使实现方法定义为Task并且其中有async个调用..直到第一个离开,默认情况下一切都是同步的。

因此所有选项的结果都是相同的:立即抛出或返回已经完成但带有异常的任务(如果等待立即调用,则行为相同)或标记方法await(这将是希望您有async个电话,但我们会将其添加为完整性。

我会立即投掷,因为返回任务可能表示您已经开始工作了#34;并且来电者不需要等待任务,所以如果来电者并不真正关心你的await何时完成(它甚至没有返回值),该方法未实现的事实不会出现。

答案 2 :(得分:2)

在你的评论中,你写道:

  

我们正在尝试制作NHibernate的异步版本:)

这让你处于一个不幸的位置:熟练的程序员编写的知名图书馆应该写得好,以防止不太熟练的程序员意外误用(包括通过复制/粘贴滥用)。

有足够多的人希望await Task.WhenAll(a(), b(), c())之类的代码能够工作,即使其中一个异步操作失败,我也说你的第一个选项甚至不应该是一个选项。如果b()同步抛出异常,则忽略a()返回的任务,并且不会调用c()

我同意Stephen Cleary的回答说NotImplementedException正如他所说的那样,是一个无关紧要的愚蠢例外,因为它无论如何都不应该以生产代码结束。但是,你写道:

  

此问题也适用于NotSupportedExceptionInvalidOperationException

这些不一定是愚蠢的例外。这些可能最终出现在生产代码中。

您的第二个选择可以避免这个问题。

您的第二个选项确实存在其他问题:它不会引发异常。由于实际上没有抛出任何异常,因此阻碍了调试:当出现问题时,让调试器中的选项在抛出而不是的位置处断开是非常有用的EM>捕获

我建议也考虑

public async override Task XAsync() {
  throw new NotImplementedException();
}
由于与创建状态机相关的开销而丢弃的

。我认为这不是丢弃它的正当理由。这是性能不相关的代码,这是仅处理错误情况的代码。我建议它,因为一般来说,我赞成使用async / await直接操作任务,因为它更容易捕获愚蠢的错误,因为开发时间节省的时间足够高值得。

我明白为什么你不想选择这个选项,但我个人仍然愿意。它避免了您的第一个选择的缺点。它避免了第二种选择的缺点。它本身的缺点,即性能稍慢,在我看来不太可能成为问题,而不是其他两个。

在其他两个中,希望这些缺点的细节可以帮助您做出明智的决定。