2

私は今日、内面を比較する傾向に打たれ、舞台裏で呼ばれるかどうかを知りたいBuffer.BlockCopyArray.CopyTo. 思っています。この背後にある実用的な目的はありません。C#言語とその実装方法についての理解を深めたいと思います。銃を飛び越えて私をマイクロ最適化で非難しないでください、しかしあなたは私が好奇心を持っていると非難することができます!Array.CopyToBuffer.BlockCopy

私がmscorlib.dllでILdasmを実行したとき、私はこれを受け取りましたArray.CopyTo

.method public hidebysig newslot virtual final 
    instance void  CopyTo(class System.Array 'array',
                          int32 index) cil managed
{
  // Code size       0 (0x0)
} // end of method Array::CopyTo

そしてこれはBuffer.BlockCopy

.method public hidebysig static void  BlockCopy(class System.Array src,
                                            int32 srcOffset,
                                            class System.Array dst,
                                            int32 dstOffset,
                                            int32 count) cil managed internalcall
{
  .custom instance void System.Security.SecuritySafeCriticalAttribute::.ctor() = ( 01 00 00 00 ) 
} // end of method Buffer::BlockCopy

率直に言って、これは私を困惑させます。作成していないdll/exeでILdasmを実行したことはありません。これは、これらの機能がどのように実装されているかを確認できないことを意味しますか?周りを検索すると、スタックオーバーフローの質問が明らかになっただけで、MarcGravellはそれを言いました

[ Buffer.BlockCopy]は基本的に生のmem-copyのラッパーです

Array.CopyTo洞察に満ちていますが、電話しても私の質問には答えられませんBuffer.BlockCopy。これらの2つの関数がどのように実装されているかを確認できるかどうか、およびC#の内部について将来質問がある場合は、調査できるかどうかに特に関心があります。それとも私は運が悪いのですか?

4

5 に答える 5

9

ここでの最大の問題は、投稿内容から判断して、特に.NET4のリファレンスアセンブリを見ていることです。これは特別なアセンブリであり、すべてのILが削除され、メタデータのみが含まれています。これは.NET4の新機能であり、以前のバージョンの.NETの古い問題を解決します。参照アセンブリがGACにインストールされた実際のアセンブリの単なるコピーであった場合。

これは問題を引き起こし、プログラムを壊していた後のリリースとサービスパックで変更が加えられました。特にWaitHandle.WaitOne(int)のオーバーロードは悪名高く、.NET 3.0(別名.NET 2.0 SP1)で追加されました。そして、プログラマーが無意識のうちに使用して、ヘコファロットのオーバーロードが、神秘的なWaitOne(int、bool)オーバーロードよりも使いやすいことを発見しました。ただし、プログラムが元の.NET 2.0リリースバージョンで実行されなくなり、MissingMethodExceptionが発生するという問題があります。

このオーバーロードを追加することは、一般的にかなりやんちゃなことでした。彼らはmscorlib.dllを変更しましたが、その[AssemblyVersion]は変更しませんでした。.NET 4で個別の参照アセンブリを提供することにより、この問題は発生しなくなります。Microsoftは、何も壊すことなく.NETタイプのパブリックインターフェイスを変更できるようになりました。そして、これを好意的に行って、いくつかの.NET4中間リリースが誰にも気付かれることなくスリップストリーム化されました。

したがって、GACにあるmscorlib.dllの実際のバージョンを必ず分解してください。.NET 4の場合、c:\ windows \ assemblyではなくc:\ windows \ microsoft.net\assemblyという別のディレクトリに保存されます。エクスプローラーシェルの名前空間拡張機能によって保護されなくなった場合は、[ファイル]+[開く]を使用してGACディレクトリを参照できます。32ビットバージョンは、C:\ Windows \ Microsoft.NET \ assembly \ GAC_32 \ mscorlib\v4.0_4.0.0.0__b77a5c561934e089ディレクトリにあります。

これで話は終わりではありません。ドリルダウンすると、Array.CopyTo()が[MethodImpl(MethodImplOptions.InternalCall)]属性を持つArray.Copy()という名前の内部ヘルパーメソッドを呼び出していることがわかります。繰り返しますが、メソッド本体はありません。この属性は、メソッドが実際にCLR内のC++で実装されていることをジャストインタイムコンパイラに通知します。このようなメソッドのソースコードを確認する方法については、この回答を参照してください。

于 2012-06-02T16:50:27.803 に答える
4

ILSpyは、無料の.NETデコンパイラーです。これを使用して、mscorlibを含む任意の.NETDLLを調べることができます。

Array.CopyToを呼び出しますArray.CopyArray.CopyとはどちらBuffer.BlockCopyexternメソッドです。つまり、マネージド.NETコードではなくネイティブコードで定義されているため、これらがどのように機能するかについてはこれ以上説明できません。

于 2012-06-02T16:27:36.443 に答える
1

私は自分の質問に答えるつもりです。これは悪いスタイルだと思いますが、以前の回答から得られた素晴らしいリソースがなければ、回答を作成することはできませんでした。ありがとうございました。

まず、ここに来て、一般的にC#関数の内部を検査する方法を考えている人は、TimがすばらしいリソースILSpyを投稿しました。これは、メソッドが外部で定義されていない場合に機能します。それらが外部で定義されている場合、答えを得る唯一の希望は、SSCLI2.0をダウンロードすることであるように思われます。これは4.0ではなく.Net2.0を対象としているため、私が提示する情報は古くなっている可能性があります。ただし、問題の方法はあまり変わっていないという前提で続けます。ソースファイルを調べた後、「Array.CopyToは舞台裏でBuffer.BlockCopyを呼び出しますか?」という質問に答えられると思います。</ p>

問題の核心に入る前に、CopyToがArray.Copyを呼び出すことを他の人が指摘しました。Array.Copyは外部で定義されているので、クエリを「Array.Copyは舞台裏でBuffer.BlockCopyを呼び出しますか?」に変更します。私が興味深いと思ったちょっとした情報は、MSDNのArray.CopyToのドキュメントからのものです。

System.Collections.ICollectionを明示的に実装する必要がない場合は、[Array。]Copyを使用して余分な間接参照を回避します。

各関数が実行するために真でなければならないチェックのタイプを区別させてください。

BlockCopy:

  1. 宛先とソースをnullにすることはできません
  2. Destination配列とSource配列は、プリミティブまたは文字列で構成されていますが、オブジェクトは含まれていません。
  3. 長さとオフセットは有効である必要があります

Array.Copy:

  1. 宛先とソースをnullにすることはできません
  2. 宛先とソースは配列である必要があります
  3. メソッドテーブルとランクを使用したいくつかのチェック
  4. もう少し詳細な長さとオフセットのチェック
  5. タイプは何らかの形で一致する必要があります(アン/ボクシング、キャスト、または拡張のいずれか)

これらのチェックの後、BlockCopyはm_memmoveを呼び出します。これは自明ですが、非常に興味深いものです。m_memmoveはアーキテクチャに依存します。32ビットマシンでの従来のmemmoveを廃止し、一度に16バイトをロールするハンドコピーを採用しました。

想像できるように、配列は単なるプリミティブ以上のものを保持します。

  • ソース配列と宛先配列が同じタイプの場合、コピーはm_memmoveを呼び出します。次に、基になる型がプリミティブでない場合、ガベージコレクションアクションが実行されます。
  • それ以外の場合、渡される要素のタイプに応じて、コピーは各要素を転送するときに、各要素のボックス化を解除、ボックス化、キャスト、または拡張します。これらの関数は、私が知る限り、m_memmoveを呼び出さず、代わりに各要素を一度に1つずつ変換します。

したがって、私の元の質問に答えるために、「Array.Copyは舞台裏でBuffer.BlockCopyを呼び出しますか?」ある意味、2つの方法がm_memmoveを処理する際に共通している類似点を考慮すると。BlockCopyは常にm_memmoveを呼び出しますが、Copyはまったく同じタイプの配列を処理している場合にのみ呼び出します。次に、バイトの配列をintにコピーする場合、または生データを気にする場合は、m_memmoveを利用できるため、BlockCopyを使用することをお勧めします。

参考:.Netがプリミティブとして定義するもの(cortypeinfo.hから取得)

  1. 空所
  2. ブール
  3. チャー
  4. 符号付きバイトと符号なしバイト
  5. 符号付きおよび符号なしの短い
  6. 符号付きおよび符号なしint
  7. 長い署名と署名なし
  8. フロートとダブル
  9. 符号付きおよび符号なしIntPtr
  10. ELEMENT_TYPE_R(これが何であるかわからない)
于 2012-06-03T01:10:34.613 に答える
0

Buffer.BlockCopyでTelerikJustDecompileを使用すると、次のことがわかります。

[SecuritySafeCritical]
public static extern void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count);

つまり、ILコードを生成するものを使用して実装されていないということです。

そしてArray.CopyTo:

public void CopyTo(Array array, int index) {
  if (array != null && array.Rank != 1) {
    throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
  }
  Array.Copy(this, this.GetLowerBound(0), array, index, this.Length);
}

Array.Copyは次のことを明らかにします:

[SecuritySafeCritical]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length) {
  Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length, false);
}

その過負荷:

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

したがって、これもILコードではありません。

メソッドを調べたい場合は、逆アセンブラを引き出す必要があります。

于 2012-06-02T16:35:07.763 に答える
0

Array.CopyToとの両方Buffer.BlockCopyが(最終的に)疑似属性で実装されます。

[MethodImpl(MethodImplOptions.InternalCall)]

このページの一般的な賢者であるStevenToubからの2番目の質問を見ると、これが何を意味するのかについての優れた説明があります。

于 2012-06-02T17:08:58.047 に答える