(データベースからの)オブジェクトのリストを含むビューモデルのプロパティを公開したいと思います。
このコレクションを読み取り専用にする必要があります。つまり、追加/削除などを防止したいのですが、foreachとインデクサーが機能するようにします。私の意図は、編集可能なコレクションを保持するプライベートフィールドを宣言し、読み取り専用のパブリックプロパティで参照することです。次のように
public ObservableCollection<foo> CollectionOfFoo {
get {
return _CollectionOfFoo;
}
}
ただし、その構文は、コレクションへの参照の変更を妨げるだけです。追加/削除などを妨げるものではありません。
これを達成するための正しい方法は何ですか?
[以前]受け入れられた回答は、ReadOnlyFooにアクセスするたびに、実際にはdifferentReadOnlyObservableCollectionを返します。これは無駄であり、微妙なバグにつながる可能性があります。
望ましい解決策は次のとおりです。
public class Source
{
Source()
{
m_collection = new ObservableCollection<int>();
m_collectionReadOnly = new ReadOnlyObservableCollection<int>(m_collection);
}
public ReadOnlyObservableCollection<int> Items
{
get { return m_collectionReadOnly; }
}
readonly ObservableCollection<int> m_collection;
readonly ReadOnlyObservableCollection<int> m_collectionReadOnly;
}
詳細については、 ReadOnlyObservableCollectionアンチパターン を参照してください。
ReadOnlyObservableCollection<T>
は間違い/壊れたクラスのように見えるので、使用するのは好きではありません。代わりに、契約ベースのアプローチを好みます。
共分散を可能にするために私が使用するものは次のとおりです。
public interface INotifyCollection<T>
: ICollection<T>,
INotifyCollectionChanged
{}
public interface IReadOnlyNotifyCollection<out T>
: IReadOnlyCollection<T>,
INotifyCollectionChanged
{}
public class NotifyCollection<T>
: ObservableCollection<T>,
INotifyCollection<T>,
IReadOnlyNotifyCollection<T>
{}
public class Program
{
private static void Main(string[] args)
{
var full = new NotifyCollection<string>();
var readOnlyAccess = (IReadOnlyCollection<string>) full;
var readOnlyNotifyOfChange = (IReadOnlyNotifyCollection<string>) full;
//Covarience
var readOnlyListWithChanges =
new List<IReadOnlyNotifyCollection<object>>()
{
new NotifyCollection<object>(),
new NotifyCollection<string>(),
};
}
}
プロパティのタイプをIEnumerableに変更できます。
public IEnumerable<foo> CollectionOfFoo {
get {
return _CollectionOfFoo;
}
}
インデクサーを公開する標準のインターフェースがあるとは思いません。必要に応じて、インターフェースを作成し、ObservableCollectionを拡張して実装できます。
public interface IIndexerCollection<T> : IEnumerable<T>
{
T this[int i]
{
get;
}
}
public class IndexCollection<T> : ObservableCollection<T>, IIndexerCollection<T>
{
}