3

これが可能かどうかはわかりませんが、サイズを計算して基本クラスに保存し、その結果を読み取り専用としてサブクラスに公開する必要があります。サイズ自体を読み取り専用にするのは、次のように、保護されたゲッターとプライベート セッターを使用してプロパティの背後に隠すことで簡単です...

private Size _someSize;
protected Size SomeSize
{
    get{ return _someSize; }
    private set{ _someSize = value; }
}

次に、基本クラス内から、次のように設定できます...

SomeSize = new Size(23.0, 14.7);

...しかし、セッターは基本クラスに対してプライベートであるため、サブクラスクラスからそれを行うことはできません。

ただし、サブクラスが Size 構造体のメンバーを変更できるようにもしたくありません。

アップデート

サブクラスで、これをコンパイルしてみると・・・

SomeSize.Width = 17.0;

...「変数ではないため、SomeSize の戻り値を変更できません」というエラーが表示されるため、期待どおりに基本クラスの値が保護されます。

それでも、ゲッターが真の読み取り専用構造を返すようにする方法を誰かが理解できる場合 (そのようなことが可能な場合でも、私は疑います)、答えを提供します。確かに、それは実際にはこの問題には必要ありませんでしたが、それが可能かどうかを知ることは良いことです。

4

2 に答える 2

5

あなたが提案したものはすでにあなたのニーズを満たしているので、あなたはそれをコンパイルしようとしなかったに違いありません。Size型は(参照型)structureではなく (値型)classであるため、プロパティ ゲッターは、参照ではなく、_someSize に格納されている値のコピーを返します。したがって、サブクラスが実際にSomeSize.Widthプロパティを変更しようとしても、実際にはプライベート _someSize 変数に触れていません。返された値のコピーを変更するだけです。ただし、コンパイラはこれが無効であることを認識しているため、次の行をコンパイルすることさえできません。

SomeSize.Width = 17.0;

値を変更してコンパイルできるようにする唯一の方法は、次のようになります。

Size temp = SomeSize;
temp.Width = 17.0;

しかし、私が言ったように、それは値の単なるコピーであるため、実際にはSomeSizeプロパティの値を変更しません.--の値のみを変更しますtemp.

ただし、Size型がクラスの場合は、元のオブジェクトへの参照ではなく、オブジェクトのクローンを返すだけで、同じ種類の保護を実現できます。たとえばSize、 が実際には次のようなクラスだった場合:

public class MySize
{
    public MySize(float height, float width)
    {
        Height = height;
        Width = width;
    }

    public float Height { get; set; }
    public float Width { get; set; }

    public MySize GetCopy()
    {
        return (MySize)MemberwiseClone();
    }
}

プロパティは読み取り専用ではありませんが、次のように疑似読み取り専用プロパティを作成できます。

private MySize _someSize;
protected MySize SomeSize
{
    get { return _someSize.GetCopy(); }
    private set { _someSize = value; }
}

ただし、返されたオブジェクトのプロパティを読み取り専用にしたい場合は、元の型の独自の読み取り専用バージョンを実装するしかありません。たとえば、List<T>タイプはそれ自体の読み取り専用バージョンを取得する機能をサポートしているため、それを読み取り専用リスト プロパティに使用できます。組み込みの機能があるためList<T>、次のようなことを簡単に行うことができます。

private List<string> _list = new List<string>();
public ReadOnlyCollection<string> List
{
    get { return _list.AsReadOnly(); }
}

ただし、ご覧のとおり、このメソッドはオブジェクトAsReadOnlyを返しません。List<T>代わりにReadOnlyCollection、リストの読み取り専用バージョンとしてカスタム作成されたまったく新しいタイプのオブジェクトを返します。つまり、真に読み取り専用Sizeプロパティを作成する唯一の方法は、次のReadOnlySizeように独自の型を作成することです。

public struct ReadOnlySize
{
    public ReadOnlySize(Size size)
    {
        _size = size;
    }

    private Size _size;

    public float Height 
    {
        get { return  _size.Height; } 
    }

    public float Width
    {
        get { return _size.Width; }
    }
}

そして、次のように読み取り専用プロパティを作成できます。

private Size _someSize;
public ReadOnlySize SomeSize
{
    get { return new ReadOnlySize(_someSize); }
}
于 2012-12-31T10:36:45.033 に答える
0

.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ではなくを高さに追加した場合、入力するたびに保持するクロージャーを生成する必要がありました)。メソッド呼び出しが実行されるたびにデリゲートを生成する必要がありました; 量をパラメーターとして渡すことで、そのオーバーヘッドを回避できます)。refadderHeightAdderref

アクセスメソッドにインデックスまたはキーのパラメーターが含まれている場合、同様のアプローチを、同様のクラスで使用するList<T>Dictionary<TKey,TValue>、コールバックメソッドがリストスロットまたはディクショナリエントリに対して直接動作できるようにすることができます。

このアプローチの優れた機能の 1 つは、他の方法では困難な同時アクセスのスタイルをコレクションで提供できることです。コレクション内のものがInterlockedメソッドで使用できる型 (または、フィールドがそのようなメソッドで使用できる公開構造体型) である場合、クライアント コードはそのようなメソッドを使用して、基になるデータに対してスレッド セーフなアトミック操作を実行できます。コレクション内のものがそのようなタイプでない場合、コレクションは、他のアプローチよりも安全にロックを実装できる可能性があります。たとえば、aには;ConcurrentIndexedSet<T>のファミリがある場合があります。ActOnItem(int item, int timeout, ActByRef<T> proc)ロック内のアイテムで呼び出すメソッドproc(クライアント提供のproc妥当な期間内に戻ると信頼できます)。このようなコードは、procデッドロックやその他の方法で待ち伏せされる可能性を防ぐことはできませんでしたが、呼び出し元のコードに制御を返す前にロックが解放されることを保証できました。

于 2013-01-01T18:55:59.290 に答える