2009-03-06 24 views
19

私は以下のクラスがあります。C#でプロパティアクセサ「読み取り専用」

class SampleClass 
{ 
    private ArrayList mMyList; 

    SampleClass() 
    { 
     // Initialize mMyList 
    } 

    public ArrayList MyList 
    { 
     get { return mMyList;} 
    } 
} 

私は、ユーザーが私が露出理由ですmMyListを取得できるようにしたいのが、私にはない性質を経由して「取得」オブジェクトに加えた変更(MyList.Add(new Class());)を自分のクラスに戻したい

私はオブジェクトのコピーを返すことができますが、遅くなる可能性があります、私はコンパイル時にエラーを提供する方法を探しています。プロパティから返された値。

これは可能ですか?

+0

関連質問することです/ questions/681287/how-to-make-a-reference-type-property-readonly –

+2

.NET 4.5の 'List :ReadOnlyCollection 'はこれを変更しますか? http://www.infoq.com/news/2011/10/ReadOnly-WInRT/ –

答えて

25

ArrayListでは、BCLに読み取り専用の非ジェネリックコレクションクラスがないため、かなり制限されています。速くて汚い解決策は、IEnumerableの型を返すことです。

public IEnumerable MyList 
    { 
     get { return mMyList;} 
    } 

この

は実際にはArrayListにキャストから誰かを防ぐことはできませんが、それはあなたがArrayList.ReadOnlyを呼び出すことにより、効果的に読み取り専用のリストを返すことができ、デフォルトのいずれか

によって編集を許可しません。しかし、戻り値の型はArrayListなので、ユーザーは.Addでコンパイルできますが、ランタイムエラーが発生します。

1

読み取り専用コレクションに戻り値をラップする必要があります。

19

ArrayList.ReadOnly()メソッドを使用して、リストの周囲に読み取り専用ラッパーを作成して返します。リストをコピーするのではなく、単純にその周りに読み取り専用ラッパーを作成します。コンパイル時のチェックを行うためには、読み込み専用のラッパーを@JaredのようにIEnumerableとして返すことをお勧めします。

public IEnumerable MyList 
{ 
    get { return ArrayList.ReadOnly(mMyList); } 
} 

読み取り専用であるコレクションは、単に コレクションを変更防止ラッパー のコレクションです。基になるコレクション が変更された場合、読み取り専用の コレクションにはこれらの変更が反映されます。

このメソッドはO(1)操作です。

Reference

+2

私はこの解決策に反対しています。なぜなら、コンパイル時のエラーであるべきものが実行時エラーになるからです。 – JaredPar

+0

-1、OP:「**コンパイル時エラー**を提供する方法を探しています」 –

+0

ReadOnlyCollectionにコピーせずに - 彼は避けたかったと言いました - 私は、読んでいるだけのふりをする。両方をすることはおそらくおそらくより良いでしょう。 – tvanfosson

-3

ただ、このように、読み取り専用封印されたとして財産を作る(またはVB.NETでNotInheritable)と:

public sealed readonly ArrayList MyList 
    { 
     get { return mMyList;} 
    } 

はまた、読み取り専用としてバッキングフィールドを作成することを忘れないでください:

private readonly ArrayList mMyList; 

mMyListの値を初期化するには、コンストラクタでのみ初期化する必要があります。この例では:

public SampleClass() 
{ 
    // Initialize mMyList 
    mMyList = new ArrayList(); 
} 
10

ちょうどJaredParの答えを拡張してください。ユーザーがIEnumerableArrayListに動的にキャストできるため、実際のバッキングフィールドを返すことは完全に安全ではありません。私は元のリストへの変更が行われていないことを確認するため、このような何かを書くと

public IEnumerable MyList 
{ 
    get 
    { 
     foreach (object o in mMyList) 
      yield return o; 
    } 
} 

その後、再び、私はprobabilyも完全に安全と入力するジェネリックリスト(IEnumerable<T>)を使用します。

+0

*これは正しいものです。私は2回投票することができれば幸いです。ループの後に 'yield break;'を呼び出さなかった場合の問題はありますか? – Jay

+0

@Jay:ループの後に明示的に「yield break;」の必要はありません。メソッドの終わりは 'Enumerator'の終わりを意味します(そして' MoveNext'は正しく 'false'を返します)。 –

+0

このソリューションでは、高速ランダムアクセスや高速カウントなど、ArrayListの機能が失われることはありませんか? –

4

ReadOnlyCollectionを使用してください。

return new ReadOnlyCollection<object>(mMyList)

また、ReadOnlyCollectionをフィールドにすることもできます。これにより、下位のリストの変更が自動的に反映されます。これが最も効率的なソリューションです。

mMyListに1つのタイプのオブジェクト(DateTimes以外)が含まれていることが分かっている場合は、 を追加タイプの安全性のためにReadOnlyCollection<DateTime>(または他のタイプ)に戻すことができます。あなたがC#3を使用している場合は、単に

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

を書くことができますしかし、これは自動的に基本的なリストを更新しません、また、あまり効率的である(これは、リスト全体をコピーします) 。 http://stackoverflow.com:最良のオプションは、mMyListジェネリックList<T>(例えば、List<DateTime>

0
.NET v2.0のから入手可能

public ArrayList MyList { get; private set; } 
+0

既存のリストに[追加]を使用することはできます。 –

関連する問題