2009-07-31 122 views
32

another question我問,一個評論出現,指出.NET框架的Array.Copy方法使用非託管代碼。我去Reflector挖掘,發現簽名Array.Copy方法重載的一個被定義爲這樣:C#內部靜態外部與InternalCall屬性 - 內部或外部?

[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)] 
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable); 

看着這之後,我稍微困惑。我的混亂的來源是extern改性劑,這意味着(MSDN鏈路):

的extern修飾符用於聲明 被實現 外部的方法。

然而,該方法聲明還裝飾有一個MethodImplOptions.InternalCall屬性,其指示(MSDN鏈路):

指定內部呼叫。內部呼叫是對方法 的調用,該方法在通用的 語言運行時本身內實施。

任何人都可以解釋這個看似明顯的矛盾嗎?

回答

46

我剛纔對leppie's發表了評論,但是它有點長了。

我目前正在研究一個實驗性的CLI實現。在很多情況下,如果沒有關於虛擬機如何在內部實現的知識,公開暴露的方法(或屬性)就無法實現。一個例子是OffsetToStringData,它需要知道內存管理器如何分配字符串。

對於這樣的情況,如果沒有C#代碼來表示方法,則可以將特定方式的每個調用以內部作爲JIT進程的對待方式。作爲一個例子,在將call字節代碼傳遞給本地代碼生成器之前,用ldc.i4(加載常量整數)代替call字節代碼。 InternalCall標誌表示「此方法的主體由運行時本身以特殊方式處理」。可能有也可能沒有實際的實現 - 在我的代碼中,有幾種情況下JIT會將該調用視爲intrinsic

還有其他一些情況下,JIT可能有特殊的信息可用,可以對方法進行重度優化。一個例子是Math方法,其中即使這些can be implemented in C#,指定InternalCall使它們有效地具有內在性具有顯着的性能優點。

在C#中,一個方法必須有一個主體,除非它是abstractexternextern意味着一個通用的「你可以從C#代碼調用這個方法,但它的主體實際上是在其他地方定義的。」當JIT接到對extern方法的調用時,它會查找哪裏可以找到主體,並根據結果以不同的方式運行。

  • DllImport屬性指示JIT製作P/Invoke存根以調用本機代碼實現。
  • InternalCall標誌指示JIT以自定義方式處理呼叫。
  • (有一些人,但我沒有把我的頭頂部供他們使用的例子。)
15

InternalCall表示由框架提供。

extern說你不提供代碼。

extern可用於2種一般情況,如上述,或與p/invoke。

使用p/invoke,您只需告訴方法從哪裏獲得實現。

+0

@leppie - 我想我可能標誌着雙方你和280Z28的回答,因爲你作爲公認的」都是正確的。但是,我認爲280Z28的答案能夠更清楚地說明問題,並幫助我更好地理解,但是,非常感謝您的努力。 – CraigTP 2009-07-31 12:52:54