.net 言語における構造体型の主な制限の 1 つは、書き込み可能な構造体型の格納場所 (変数、フィールド、パラメーター、配列スロットなど) のフィールド自体が書き込み可能な格納場所である (構造体型の場合) ことです。 、それらのフィールドは同様に書き込み可能な保存場所です)、そのようなアクセスは構造体型の保存場所でのみ機能し、保存場所のように機能するプロパティSystem.Array
を公開できるタイプ以外の方法はありません。
ref
提供されたコールバックにそのストレージの場所をパラメーターとして渡すことができるメソッドをクラスが提供する場合、クラスは制御された状況下で非公開のストレージの場所をストレージの場所として公開することができます。
例えば:
public delegate void ActByRef<T1>(ref T1 p1);
public delegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
public delegate void ActByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3);
public void ActOnSize(ActByRef proc)
{ proc( ref _someSize); }
public void ActOnSize<XT1>(ActByRef proc, ref XT1 xp1)
{ proc( ref _someSize, ref xp1); }
public void ActOnSize<XT1,XT2>(ActByRef proc, ref XT1 xp1, ref XT2 xp2)
{ proc( ref _someSize, ref xp1, ref xp2); }
そのようなメソッドを公開したものの幅に 5 を追加したい場合は、次のように使用できます。
thing.ActOnSize((ref Size sz) => sz.Width += 5);
ローカル変数「HeightAdder」があり、それをオブジェクトの高さに追加したい場合は、次を使用できます
thing.ActOnSize((ref Size sz, ref int adder) =>
sz.Height += adder, ref HeightAdder);
記述されたラムダ式はローカル変数をキャプチャしないため、静的デリゲートとして評価される可能性があることに注意してください (デリゲートがパラメーターHeightAdder
ではなくを高さに追加した場合、入力するたびに保持するクロージャーを生成する必要がありました)。メソッド呼び出しが実行されるたびにデリゲートを生成する必要がありました; 量をパラメーターとして渡すことで、そのオーバーヘッドを回避できます)。ref
adder
HeightAdder
ref
アクセスメソッドにインデックスまたはキーのパラメーターが含まれている場合、同様のアプローチを、同様のクラスで使用するList<T>
かDictionary<TKey,TValue>
、コールバックメソッドがリストスロットまたはディクショナリエントリに対して直接動作できるようにすることができます。
このアプローチの優れた機能の 1 つは、他の方法では困難な同時アクセスのスタイルをコレクションで提供できることです。コレクション内のものがInterlocked
メソッドで使用できる型 (または、フィールドがそのようなメソッドで使用できる公開構造体型) である場合、クライアント コードはそのようなメソッドを使用して、基になるデータに対してスレッド セーフなアトミック操作を実行できます。コレクション内のものがそのようなタイプでない場合、コレクションは、他のアプローチよりも安全にロックを実装できる可能性があります。たとえば、aには;ConcurrentIndexedSet<T>
のファミリがある場合があります。ActOnItem(int item, int timeout, ActByRef<T> proc)
ロック内のアイテムで呼び出すメソッドproc
(クライアント提供のproc
妥当な期間内に戻ると信頼できます)。このようなコードは、proc
デッドロックやその他の方法で待ち伏せされる可能性を防ぐことはできませんでしたが、呼び出し元のコードに制御を返す前にロックが解放されることを保証できました。