2017-05-04 60 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,因爲捕捉愚蠢的錯誤容易得多,因爲在開發時節省的時間足夠高以至於值得。

我明白你爲什麼不想用這個選項,但我個人仍然會。它避免了你的第一個選擇的缺點。它避免了第二種選擇的缺點。它本身的缺點,稍微慢一點的表現,根據我的經驗,比其他兩個更不容易成爲問題。

在其他兩個中,希望詳細的缺點幫助您做出明智的決定。