2010-11-17 58 views

回答

4

您可以遵循這些簡單的規則逐一確定你應該使用:

  • 是方法static?然後使用call
  • 是您在值類型上調用的類型?然後使用call。 (這適用,如果該值盒裝 - 那麼你實際上是在調用上object或一些接口,而這些都是引用類型。)
  • 是要調用聲明virtualabstract的方法?然後使用callvirt
  • 您是否正在通過接口引用調用該方法?然後使用callvirt
  • 您調用的方法是否被聲明爲override,但方法和聲明類型均未聲明sealed?然後使用callvirt

在其他情況下,沒有虛擬調度是必需的,所以你可以使用call - 但你應該使用callvirt。原因如下:

在非虛擬方法上使用callvirt相當於call,除非第一個參數爲空。在這種情況下,callvirt將立即拋出NullReferenceException,而call不會。這是有道理的,因爲callvirt旨在用於需要虛擬方法調度的情況,並且如果沒有用於執行vtable查找的對象,則不能執行虛擬方法調度。

請注意,即使不需要vtable查找,如果第一個參數爲空,callvirt仍然會引發異常!

考慮該信息,使用callvirt對引用類型的所有非靜態方法調用(如C#編譯器一樣)可以是優選的,因爲它會立即導致一個NullReferenceException在調用位置,而不是一段時間後,當this被使用(顯式或隱式地)在方法內部。

+0

但.NET在調用類似Point.X時使用「call」。從我正在閱讀的顯然值類型方法使用「呼叫」。 – Will 2010-11-17 23:46:21

+2

是的,因爲這些方法不是虛擬的,所以我希望輸出使用「呼叫」。再次閱讀我的答案。 (另外,structs *不能*具有虛擬成員,因爲它們不能被繼承。) – cdhowie 2010-11-17 23:47:28

+0

這很有道理,謝謝。奇怪的是,反射顯示「IsVirtual」對於結構方法是真實的。 – Will 2010-11-17 23:55:24

6

默認情況下,除靜態或值類型調用外,C#編譯器始終對callvirt使用callvirt。這會導致'this'(arg0)參數的隱式空檢查。你並沒有嚴格遵守這個約定,但是任何引用類型的虛擬方法肯定會需要callvirt。

+1

除密封類上的虛擬方法外。 – 2015-03-11 21:09:20

0

如果您在虛擬方法的動態方法中使用調用,則運行時將引發安全異常。