はい、コンパイラ、ジッタ、および CLR の 3 つ組には、配列に関する多くの知識が組み込まれています。これはどの言語ランタイムにとっても非常に重要であり、プロセッサの機能を無視することはできません。コードを効率的に実行するには、プロセッサが適切に実行できるものにマップする必要があります。
それほど多くはありませんが、プロセッサはかなり単純なデバイスです。プログラムで使用したい種類のデータ構造を実際にサポートするものではありません。言語とランタイムの設計方法は、基盤となるプロセッサの実装に関する多くの詳細を示しています。
たとえば、スタックの概念はどこにでもあります。プロセッサがスタック ポインタを介して直接アクセスできる少量のメモリ。これが、ほとんどの言語と同様に、C# 言語がメソッド内にローカル変数の概念を持っている理由です。これは、スタックに格納される変数です。プロセッサは、単一の値を返す引数を使用してメソッドを呼び出すという概念も強力にサポートしており、ほぼすべての言語で共通です。スタックに割り当てられた少量のメモリが、このサイトの名前の由来です。
値の型は、基になるプロセッサの詳細のもう 1 つの .NET 例です。それらは、値を処理するときにプロセッサが得意とするものに直接マップされます。たとえば、int はプロセッサ レジスタに直接マップされます。float と double は、これらの値を格納し、これら 2 つの型を使用して浮動小数点命令を実行するプロセッサの機能に直接マップされます。
そして配列は、プロセッサがサポートできる唯一のデータ構造です。非常に単純で、そのメモリにアクセスするためのポインタを持つメモリのチャンクです。 可能な限り効率的にするために、.NET で大幅に最適化されています。特別に扱われる配列型である「ベクトル」に特にうなずきます。開始インデックスが 0 の 1 次元配列で、プロセッサ サポートに直接マップされる配列タイプです。あなたはC#でベクトルを取得しますtype[]
宣言。.NET では、0 以外の開始インデックスを持つ配列を作成することが非常に困難な場合、配列の制限も確認できます。非常に正当な理由により、そのような配列のインデックス作成は、マップするために追加の減算が必要になるため、コストがかかります。メモリのチャンクへのインデックス。配列インデックス チェックは最適化のもう 1 つの強力なターゲットです。境界チェックはコストがかかります。ループが範囲外の配列にインデックスを付けることは決してできないことを認識するジッターに組み込まれた多くのスマート機能により、インデックス チェックを完全に排除できます。
データ構造はすべて、ベア配列のみをサポートするプロセッサの上に構築する必要があります。これが、.NET コレクション クラス内で行われる理由です。高速化するためにできることはほとんどないため、CLR やジッターからの追加の支援はありません。また、これらのコレクション クラスがすべてベクトル配列の上に構築されている理由もあります。List<> のように、データ アルゴリズムの教科書で見られるようなリストではなく、実際には配列です。または、Dictionary<> は配列の対蹠地ですが、配列とともに実装されています。