“読み取り専用” C#のプロパティアクセサー
-
03-07-2019 - |
質問
次のクラスがあります:
class SampleClass
{
private ArrayList mMyList;
SampleClass()
{
// Initialize mMyList
}
public ArrayList MyList
{
get { return mMyList;}
}
}
ユーザーがmmyListを取得できるようにしたいので、「get」を公開しました。しかし、プロパティを介して、オブジェクトに変更を加えたくない(つまり、MyList.Add(new Class());)が私のクラスに戻ることを望みません。
私はオブジェクトのコピーを返すことができると思いますが、それは遅くなる可能性があり、返されたファイルを変更できないとユーザーに通知するコンパイル時エラーを提供する方法を探していますプロパティからの値。
これは可能ですか?
解決
ArrayListを使用すると、BCLに読み取り専用の非ジェネリックコレクションクラスがないため、かなり制限されます。迅速で汚い解決策は、IEnumerableの型を返すことです。
public IEnumerable MyList
{
get { return mMyList;}
}
これは、実際には誰かがArrayListにキャストするのを妨げませんが、デフォルトでは編集も許可しません
ArrayList.ReadOnlyを呼び出すことにより、効果的な読み取り専用リストを返すことができます。ただし、戻り値の型はArrayListであるため、ユーザーは.Addでコンパイルできますが、実行時エラーが発生します。
他のヒント
ArrayList.ReadOnly()リストの周りに読み取り専用のラッパーを構築して返すメソッド。リストはコピーされませんが、単に読み取り専用のラッパーを作成します。コンパイル時のチェックを取得するには、おそらく@Jaredが示唆するように、IEnumerableとして読み取り専用ラッパーを返します。
public IEnumerable MyList
{
get { return ArrayList.ReadOnly(mMyList); }
}
読み取り専用のコレクションは ラッパーを備えた単純なコレクション それは変更を防ぎます コレクション。変更が行われた場合 基礎となるコレクション、読み取り専用 コレクションはそれらの変更を反映しています。
このメソッドはO(1)操作です。
JaredParの回答をさらに詳しく説明します。彼が言ったように、ユーザーは IEnumerable
を ArrayList
に動的にキャストできるため、実際のバッキングフィールドを返すことは完全に安全ではありません。
元のリストが変更されていないことを確認するために、次のように記述します。
public IEnumerable MyList
{
get
{
foreach (object o in mMyList)
yield return o;
}
}
それから、完全にタイプセーフにするために、おそらく汎用リスト( IEnumerable< T>
)も使用します。
ReadOnlyCollection
を使用します。
新しいReadOnlyCollection< object>(mMyList)
を返します。
ReadOnlyCollection
をフィールドにすることもできます。これにより、基になるリストの変更が自動的に反映されます。これが最も効率的なソリューションです。
mmyListに含まれるオブジェクトのタイプが1つだけであることがわかっている場合(たとえば、DateTimesしか含まれていない場合)、
型の安全性を高めるために、 ReadOnlyCollection< DateTime>
(またはその他の型)を返すことができます。 C#3を使用している場合は、単に
新しいReadOnlyCollection< DateTime>(mMyList.OfType< DateTime>()。ToArray())を返す
ただし、これは基になるリストで自動的に更新されず、効率も低下します(リスト全体をコピーします)。最適なオプションは、mmyListを汎用の List< T>
にすることです(たとえば、 List< DateTime>
)
戻り値を読み取り専用コレクションにラップする必要があります。
.NET v2.0から利用可能
public ArrayList MyList { get; private set; }
次のように、プロパティをSealed(またはVB.NETではNotInheritable)および読み取り専用にします:
public sealed readonly ArrayList MyList
{
get { return mMyList;}
}
バッキングフィールドを読み取り専用にすることも忘れないでください:
private readonly ArrayList mMyList;
ただし、mmyListの値を初期化するには、この例のように、コンストラクターでのみ初期化する必要があります。
public SampleClass()
{
// Initialize mMyList
mMyList = new ArrayList();
}