bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] System.Collections.ObjectModel. ReadOnlyObservableCollection<T> — 変更通知付きの読み取り専用ビュー

[C#] System.Collections.ObjectModel. ReadOnlyObservableCollection<T> — 変更通知付きの読み取り専用ビュー

Jun 2, 2026 C# , .NET bucket-sort

System.Collections.ObjectModel.ReadOnlyObservableCollection<T> は、ObservableCollection<T> をラップして読み取り専用にしつつ、変更通知は伝搬する コレクションです。「内部では自由に書き換えたいが、外部からは読み取りだけにしたい」という MVVM の典型的な公開パターンを実現するための型です。

ReadOnlyObservableCollection<T> とは

  • 名前空間:System.Collections.ObjectModel
  • 基底クラス:ReadOnlyCollection<T>
  • コンストラクタは ObservableCollection<T> を受け取る
  • ラップしたコレクションへの変更通知(CollectionChanged / PropertyChanged)を そのまま外部に伝える
  • 自身は書き換え API を提供しない(呼べばコンパイルエラー or NotSupportedException)
using System.Collections.ObjectModel;

var inner = new ObservableCollection<string> { "apple", "banana" };
var view  = new ReadOnlyObservableCollection<string>(inner);

view.CollectionChanged += (s, e) =>
    Console.WriteLine($"View notified: {e.Action}");

inner.Add("cherry");
// View notified: Add

外部に渡すのは view、内部で書き換えるのは inner。読み手は変更を観測できるが、勝手に追加・削除はできません。

サポートするインターフェース

インターフェース 役割
IReadOnlyList<T> インデックスアクセスのみの読み取り専用リスト
IReadOnlyCollection<T> 読み取り専用 Count
IList<T> 互換のため実装するが書き換え API は例外
ICollection<T> 同上
IEnumerable<T> foreach での列挙
IList / ICollection / IEnumerable 非ジェネリック互換
INotifyCollectionChanged コレクション変更通知
INotifyPropertyChanged プロパティ変更通知

IList<T> を「実装はするが書き換え操作は例外を投げる」という構成は基底クラスの ReadOnlyCollection<T> の設計を引き継いでいます。コンパイル時には不変性を強制できない 点に注意してください。型としての契約は IReadOnlyList<T> が表現しています。

各インターフェースの基本については以下を参照してください。

  • IList<T> / IReadOnlyList<T>: List の記事
  • INotifyCollectionChanged / INotifyPropertyChanged: ObservableCollection の記事
  • IEnumerable<T> / IEnumerator<T>: IEnumerable と IEnumerator の記事

主な API と計算量

ReadOnlyObservableCollection<T> 自体は薄いラッパーで、内側の ObservableCollection<T> への委譲がほとんどです。

操作 API 計算量
インデックスアクセス [i] O(1)
Count Count O(1)
含有判定 Contains(item) O(n)
検索 IndexOf(item) O(n)
列挙 foreach O(n)
書き換え系 Add 等 不可(例外 or コンパイルエラー)

派生クラスとして「書き込みは内部、公開は読み取り専用」を実現する

典型的な MVVM の公開パターンは次のとおりです。

public class MainViewModel
{
    private readonly ObservableCollection<string> _items = new();

    public MainViewModel()
    {
        Items = new ReadOnlyObservableCollection<string>(_items);
    }

    public ReadOnlyObservableCollection<string> Items { get; }

    // 公開メソッドは目的別に絞った API のみ
    public void AddItem(string s)
    {
        // バリデーションなど
        _items.Add(s);
    }
}

XAML 側はこれまで通り ItemsSource="{Binding Items}" で OK。Items 経由では追加・削除ができないため、外部のコードが意図せずコレクションを書き換えるバグを防げます。

ReadOnlyCollection<T> との比較

観点 ReadOnlyCollection<T> ReadOnlyObservableCollection<T>
ラップ対象 IList<T>(List<T> 等) ObservableCollection<T>
変更通知 なし CollectionChanged / PropertyChanged を中継
バインディング自動更新 × ◯
用途 不変ビューの公開(非バインディング) バインディング対象の不変ビュー

「変更通知が要らない読み取り専用ビュー」なら ReadOnlyCollection<T> か、より厳密な不変性が必要なら ImmutableArray<T> / ImmutableList<T> を選びます。

使いどころ

  1. MVVM の公開プロパティ:ViewModel から外部(View や他のサービス)にバインディング対象を公開しつつ、書き込みは ViewModel 内部だけに閉じ込めたいとき。
  2. モデル層から UI 向けに変更追跡コレクションを渡す:変更を反映してほしいが直接書き換えてほしくない API 境界。
  3. テストでの安全性:呼び出し側が誤って Mock のコレクションに Add してしまう事故を防ぐ。

向かないケース

  • UI バインディングがない場面 → ReadOnlyCollection<T> か IReadOnlyList<T> の公開で十分。
  • 完全な不変が要件 → ImmutableArray<T> / ImmutableList<T> のほうが明確。
  • 大量データを差し替える → 内部の ObservableCollection<T> を都度差し替えるか、Reset 通知を 1 回だけ飛ばす派生型を使うのが効率的。

注意点

  • 完全な不変ではない:内部の ObservableCollection<T> は呼び出し側からは直接見えないものの、IList<T> 経由のキャストで書き込み API の実体に到達できる場合があります(((IList)view).Add(...) は NotSupportedException)。「悪意のある書き換えへの防御」ではなく「うっかりミスの防止」が主目的と理解してください。
  • イベントハンドラの解除:購読側が長命だとリークの原因になるため、-= で確実に解除する。
  • UI スレッド制約:通知は内部の ObservableCollection<T> の規約に従うため、書き込みは UI スレッドで行う/EnableCollectionSynchronization を使う、といった配慮が必要(ObservableCollection の記事 を参照)。

まとめ

  • ReadOnlyObservableCollection<T> は ObservableCollection<T> をラップして読み取り専用にしつつ変更通知を中継 するコレクション。
  • IReadOnlyList<T> / IList<T> / INotifyCollectionChanged / INotifyPropertyChanged 等を実装。
  • MVVM の公開プロパティとして使うのが定番。書き込みは ViewModel 内部の ObservableCollection<T> 側で行い、外部には読み取り専用ビューを渡す。
  • 通知不要なら [ReadOnlyCollection<T>]、完全な不変が必要なら ImmutableArray<T> / ImmutableList<T> を選ぶ。

これで System.Collections / System.Collections.Specialized / System.Collections.Generic / System.Collections.ObjectModel の主要コレクションを一通り整理しました。実務では各クラスの 性能特性とサポートインターフェース を踏まえて適切に選び分けることが、可読性と性能を両立させる近道になります。

C# .NET ReadOnlyObservableCollection System.Collections.ObjectModel WPF MVVM データバインディング
← [C#] System.Collections.ObjectModel. ObservableCollection<T> — 変更通知付きコレクションの仕組みと使いどころ [C#] ジェネリックの型制約(Constraining Type Parameters)入門 — where T : struct / class / new() / 基底クラス / インターフェース →

Related Posts

  • [C#] System.Collections.ObjectModel. ObservableCollection<T> — 変更通知付きコレクションの仕組みと使いどころ Jun 1, 2026
  • [C#] LiveChartsCoreで折れ線グラフを表示する(基本からレンジ切替まで) Jan 26, 2026
  • [C#] ジェネリックの型制約(Constraining Type Parameters)入門 — where T : struct / class / new() / 基底クラス / インターフェース Jun 3, 2026
  • [C#] System.Collections.Generic.Stack<T> — 型安全な LIFO スタックの仕組みと使いどころ May 31, 2026

Table of Contents

  • ReadOnlyObservableCollection<T> とは
  • サポートするインターフェース
  • 主な API と計算量
  • 派生クラスとして「書き込みは内部、公開は読み取り専用」を実現する
  • ReadOnlyCollection<T> との比較
  • 使いどころ
  • 向かないケース
  • 注意点
  • まとめ

Recent Posts

  • [C#] ジェネリックの型制約(Constraining Type Parameters)入門 — where T : struct / class / new() / 基底クラス / インターフェース Jun 3, 2026
  • [C#] System.Collections.ObjectModel. ReadOnlyObservableCollection<T> — 変更通知付きの読み取り専用ビュー Jun 2, 2026
  • [C#] System.Collections.ObjectModel. ObservableCollection<T> — 変更通知付きコレクションの仕組みと使いどころ Jun 1, 2026
  • [C#] System.Collections.Generic.Stack<T> — 型安全な LIFO スタックの仕組みと使いどころ May 31, 2026
  • [C#] System.Collections.Generic.SortedSet<T> — 赤黒木で実装される整列セット May 30, 2026

Categories

  • C#84
  • .NET83
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • System.Collections.Generic
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • DoS
  • Nginx
  • Windows
  • WordPress
  • メモリ管理
  • 監視
  • 設計
  • Amazon Linux 2023
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • OPCache
  • System.Collections.Specialized
  • Webサーバー
  • オブジェクト指向
  • クラス設計
  • デザインパターン
  • パターンマッチング
  • 継承
  • 認可
  • Aurora
  • Blade
  • Grafana
  • Hugo
  • InfluxDB
  • Policy
  • Record
  • SSG
  • WPF
  • インターフェース
  • エラーハンドリング
Powered by Hugo & Explore Theme.