2017-05-04 52 views
10

将异步方法标记为未实现/不支持或无效操作的正确方法是什么?为了简单起见,我将在示例中仅使用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()); 
} 

这些是什么方法的并发症?有没有更好的方法?


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


这我不考虑一些方法:

/* 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

好问题。第一个选项在调用方法时抛出异常,第二个选项在等待结果时抛出异常。我对第一种选择有一个小偏好,因为它“提前失败”,但我很好奇专家们会说些什么。 – Heinzi

+0

也许它有帮助:http:// stackoverflow。com/a/13254787/316799 –

+0

是啊,@ FelipeOriani看到了这个,谢谢 – hazzik

回答

3

当调用它的某些部分被同步执行(即使该实施方法被定义为async并且在它await呼叫..直到第一远,一切都是由缺省同步),它返回一个Task的方法,。

所以结果对于所有选项都是一样的:立即抛出或返回一个已经完成并有例外的任务(如果你立即等待电话,只表现相同)或者标记一个方法async(这会期望你有await电话,但为了完整起见我们添加它)。

我会去扔立即因为返回一个任务可能表明你“已经开始工作”和不需要呼叫者等待任务所以如果呼叫者没有真正关心时你的Task完成(它甚至没有返回值),该方法没有实现的事实不会显示出来。

+0

虽然我倾向于此...它不会建立BC没有等待 – micahhoover

+0

如果你onl y抛出一个返回任务的方法,不要使用'async'关键字定义你的方法。 –

4

我打算出去,说“没关系”。

Boneheaded exceptions可以直接投掷(throw)或放置在返回的任务(Task.FromException)。由于它们是头颅的例外,所以它们不应该被捕获,所以它们在哪里抛出都没有关系。

2

您的评论,你写道:

我们正在试图让NHibernate的:)

将你放在一个不幸的位置的异步版本:著名的图书馆由熟练编写程序员应该写得很好,以防止不熟练的程序员意外误用(包括通过复制/粘贴滥用)。

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

我同意Stephen Cleary的回答,他认为NotImplementedException正如他所说的那样,是一个头脑无关的例外,因为它永远不会在生产代码中结束。然而,你写:

该问题也适用于NotSupportedExceptionInvalidOperationException以及。

这些不一定是骨头的例外。这些可能会以结束生产代码。

你的第二个选项可以避免这个问题。

你的第二个选择有一个额外的问题:它不会引发异常。由于没有实际的异常抛出,所以你在阻碍调试:当出现问题时,在调试器中选择异常是抛出而非被捕获这一点非常有用。

我建议也考虑

public async override Task XAsync() { 
    throw new NotImplementedException(); 
} 

你因为创建一个状态机相关开销的丢弃。我认为这不是放弃它的正当理由。这是性能不相关的代码,这是只处理错误情况的代码。我建议这样做,因为一般来说,我赞成在直接操作任务上使用async/await,因为捕捉愚蠢的错误容易得多,因为在开发时节省的时间足够高以至于值得。

我明白你为什么不想用这个选项,但我个人仍然会。它避免了你的第一个选择的缺点。它避免了第二种选择的缺点。它本身的缺点,稍微慢一点的表现,根据我的经验,比其他两个更不容易成为问题。

在其他两个中,希望详细的缺点帮助您做出明智的决定。

相关问题