8

私は Jon Skeet による Edulinq を調べていて、次のコード (ページ 23) に出くわしました。このコードでは、彼Empty()は Linq のオペレーターのキャッシュメカニズムを実装しています。

private static class EmptyHolder<T>
{
   internal static readonly T[] Array = new T[0];
}

私の質問は、これが実際にどのようにArray変数をキャッシュするのですか?

オプションで、CLR でどのように機能しますか?

編集:また、それに続いて、配列を返すことに対する反乱があったと彼は述べています。配列を返してはいけないのはなぜですか (サイズが 0 であっても)?

4

2 に答える 2

13

私の質問は、これが実際に Array 変数をどのようにキャッシュするのかということです。

CLR は型引数ごとにそれをキャッシュします。基本的に、は etcEmptyHolder<int>とは異なる型であり、型初期化子は具体的なEmptyHolder<string>型ごとに (CLR によって自動的に) 呼び出されます。

そう:

var x = EmptyHolder<string>.Array; // Needs to construct the empty string[] array
var y = EmptyHolder<string>.Array; // No extra work! x and y have the same value
var z = EmptyHolder<int>.Array; // This constructs an empty array for int[]

オプションで、CLR でどのように機能しますか?

残念ながら、これは私があまり知らない実装の詳細です。しかし、基本的にこれはCLRがどのように物事を行うかについてのすべてです:)

編集:また、それに続いて、配列を返すことに対する反乱があったと彼は述べています。配列を返してはいけないのはなぜですか (サイズが 0 であっても)?

さて、次のようなコメントがありました。

配列メソッドはそれほど優れていません。文書化されていませんが、人々は戻り値が配列であることに誤って依存します。

個人的には問題ないと思いますが、代替実装を書くのは楽しかったです :)

于 2014-01-07T17:51:33.767 に答える
0

T に対して初めて EmptyHolder.Empty() を呼び出すたびに、EmptyHolder の静的コンストラクターを呼び出す必要があります。

静的コンストラクターがないように見えますよね?違う。クラスは次のように書き換えることができます...

private static class EmptyHolder<T>
{
   static EmptyHolder<T>()
   {
       Array = new T[0];
   }
   internal static readonly T[] Array;

   public IEnum<T> Empty();
}

これで、以降の Empty の実行では、静的コンストラクターは呼び出されません (別の T が使用されない限り)。

Jon Skeet を批判することはできますが、これは心配すべき小さな最適化です。

于 2013-02-06T16:29:13.137 に答える