# 通知設計書 4-INotifyCollectionChanged.CollectionChanged

## 概要

本ドキュメントは、.NET Runtimeにおける`INotifyCollectionChanged.CollectionChanged`イベント通知の設計を記述する。このイベントは、コレクションに対して項目の追加・削除・移動・置換、またはコレクション全体のリセットが行われた際にリスナーに通知を行うためのインターフェースを定義する。

### 本通知の処理概要

`INotifyCollectionChanged.CollectionChanged`イベントは、動的なデータコレクションの変更を外部のリスナーに通知するためのイベントである。このインターフェースを実装するコレクションは、要素の追加、削除、移動、置換、リセット操作時に自動的にリスナーに通知を行う。主にUIフレームワークのデータバインディングで使用され、コレクションの変更をUIに即座に反映させることを可能にする。

**業務上の目的・背景**：動的なデータを表示するリストやグリッドにおいて、コレクションの変更がリアルタイムにUIに反映されることが求められる。従来の静的なコレクションでは、変更後にUI全体をリフレッシュする必要があったが、`INotifyCollectionChanged`により増分更新が可能になり、パフォーマンスとユーザー体験が向上する。WPF、UWP、Xamarin、MAUIなどのUIフレームワークのItemsControl系コントロールで広く使用される。

**通知の送信タイミング**：コレクションに対してAdd、Remove、Move、Replace、Reset操作が行われた直後に発火する。各操作の種類に応じた`NotifyCollectionChangedAction`が設定される。

**通知の受信者**：`CollectionChanged`イベントを購読しているすべてのイベントハンドラが受信者となる。一般的にはUIフレームワークのバインディングエンジン（WPFのItemContainerGenerator等）がリスナーとなる。

**通知内容の概要**：`NotifyCollectionChangedEventArgs`オブジェクトを通じて、変更の種類（Action）、追加された項目（NewItems）、削除された項目（OldItems）、変更位置（NewStartingIndex、OldStartingIndex）が通知される。

**期待されるアクション**：受信者は変更の種類に応じて、UI上の該当項目の追加・削除・移動・更新を行う。Reset操作の場合はUI全体を再構築する。

## 通知種別

インターフェースイベント（アプリ内通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高（UIの即時更新に必要） |
| リトライ | なし（同期イベント） |

### 送信先決定ロジック

`CollectionChanged`イベントに登録されているすべてのイベントハンドラに対して、マルチキャストデリゲートとして通知が行われる。

## 通知テンプレート

### イベント引数

| 項目 | 内容 |
|-----|------|
| イベント型 | `NotifyCollectionChangedEventHandler` |
| 引数型 | `NotifyCollectionChangedEventArgs` |
| sender | イベントを発火したオブジェクト（コレクション） |

### INotifyCollectionChangedインターフェース

```csharp
public interface INotifyCollectionChanged
{
    event NotifyCollectionChangedEventHandler? CollectionChanged;
}
```

### NotifyCollectionChangedAction列挙型

```csharp
public enum NotifyCollectionChangedAction
{
    Add,      // 項目が追加された
    Remove,   // 項目が削除された
    Replace,  // 項目が置換された
    Move,     // 項目が移動された
    Reset     // コレクションがリセットされた
}
```

### NotifyCollectionChangedEventArgs

```csharp
public class NotifyCollectionChangedEventArgs : EventArgs
{
    public NotifyCollectionChangedAction Action { get; }
    public IList? NewItems { get; }        // 追加・置換後の項目
    public IList? OldItems { get; }        // 削除・置換前の項目
    public int NewStartingIndex { get; }   // 新しい項目の位置
    public int OldStartingIndex { get; }   // 古い項目の位置
}
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Action | 変更の種類 | 操作種別 | Yes |
| NewItems | 追加された項目のリスト | コレクション操作 | No（Resetの場合はnull） |
| OldItems | 削除された項目のリスト | コレクション操作 | No（Addの場合はnull） |
| NewStartingIndex | 新しい項目の開始インデックス | コレクション操作 | No（-1は未指定） |
| OldStartingIndex | 古い項目の開始インデックス | コレクション操作 | No（-1は未指定） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| プログラム実行 | Add操作 | 項目が追加された | Action=Add |
| プログラム実行 | Remove操作 | 項目が削除された | Action=Remove |
| プログラム実行 | Replace操作 | 項目が置換された | Action=Replace |
| プログラム実行 | Move操作 | 項目が移動された | Action=Move |
| プログラム実行 | Clear操作 | コレクションがクリアされた | Action=Reset |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 再入呼び出し | イベントハンドラ内でのコレクション変更は制限されることがある |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[コレクション操作の呼び出し] --> B{操作の種類}
    B -->|Add| C[InsertItem実行]
    B -->|Remove| D[RemoveItem実行]
    B -->|Replace| E[SetItem実行]
    B -->|Move| F[MoveItem実行]
    B -->|Clear| G[ClearItems実行]
    C --> H[OnCollectionChangedメソッド呼び出し]
    D --> H
    E --> H
    F --> H
    G --> H
    H --> I{CollectionChangedイベントハンドラが登録されているか?}
    I -->|No| J[終了]
    I -->|Yes| K[CollectionChangedイベントを発火]
    K --> L[各イベントハンドラが実行される]
    L --> J
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（メモリ内イベント通知）

### 更新テーブル一覧

該当なし（メモリ内イベント通知）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| InvalidOperationException | 再入呼び出しで複数のリスナーがある場合 | CheckReentrancy()で検出 |
| ArgumentException | 不正なAction値が指定された場合 | EventArgs生成時にバリデーション |
| NullReferenceException | イベントハンドラがnullの状態でInvokeを試みた場合 | null条件演算子を使用 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（制限なし） |
| 1日あたり上限 | なし（制限なし） |

### 配信時間帯

制限なし（いつでも発火可能）

## セキュリティ考慮事項

- NewItems、OldItemsにオブジェクト参照が含まれるため、メモリリークに注意
- イベントハンドラへの参照がコレクションのライフサイクルに影響を与える可能性
- マルチスレッド環境でのコレクション操作は適切な同期が必要

## 備考

- `System.Collections.Specialized`名前空間に定義
- `ObservableCollection<T>`がこのインターフェースの主要な実装
- Reset操作はパフォーマンスに影響するため、可能な限り個別操作を推奨
- WPFのListBoxやDataGridなどはこのインターフェースを使用して増分更新を行う
- 複数項目の一括追加はRange操作として最適化可能だが、標準の`ObservableCollection<T>`はサポートしていない

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | NotifyCollectionChangedEventArgs.cs | `src/libraries/System.ObjectModel/src/System/Collections/Specialized/NotifyCollectionChangedEventArgs.cs` | Action, NewItems, OldItems, インデックスプロパティの定義 |

**読解のコツ**: 複数のコンストラクタオーバーロードが存在し、各操作（Add、Remove、Replace、Move、Reset）に応じて適切なコンストラクタを使用する。

**主要処理フロー**:
1. **行14-34**: Reset用コンストラクタ
2. **行52-82**: Add/Remove用コンストラクタ（単一項目）
3. **行100-137**: Add/Remove用コンストラクタ（複数項目）
4. **行157-168**: Replace用コンストラクタ（単一項目）
5. **行210-222**: Move用コンストラクタ
6. **行248-268**: プロパティ定義

#### Step 2: インターフェース定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | INotifyCollectionChanged.cs | `src/libraries/System.ObjectModel/src/System/Collections/Specialized/INotifyCollectionChanged.cs` | インターフェースの定義（行10-21） |

**主要処理フロー**:
1. **行10**: `INotifyCollectionChanged`インターフェースの定義
2. **行11-19**: XMLドキュメントコメント（セマンティクスの説明）
3. **行20**: `CollectionChanged`イベントの宣言

#### Step 3: 実装例を理解する（ObservableCollection）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ObservableCollection.cs | `src/libraries/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs` | 各操作でのイベント発火パターン（行90-157, 183-199） |

**主要処理フロー**:
- **行84**: `CollectionChanged`イベントの宣言
- **行90-97**: `ClearItems`でのReset通知
- **行103-113**: `RemoveItem`でのRemove通知
- **行119-127**: `InsertItem`でのAdd通知
- **行133-141**: `SetItem`でのReplace通知
- **行147-158**: `MoveItem`でのMove通知
- **行183-199**: `OnCollectionChanged`メソッド（再入防止付き）

### プログラム呼び出し階層図

```
コレクション操作（例：ObservableCollection.Add）
    │
    ├─ CheckReentrancy()  // 再入呼び出しチェック
    │
    ├─ base.InsertItem(index, item)  // 実際のデータ変更
    │
    ├─ OnCountPropertyChanged()  // Countプロパティ変更通知
    │      └─ PropertyChanged?.Invoke(this, CountPropertyChanged)
    │
    ├─ OnIndexerPropertyChanged()  // Item[]プロパティ変更通知
    │      └─ PropertyChanged?.Invoke(this, IndexerPropertyChanged)
    │
    └─ OnCollectionChanged(Action.Add, item, index)
           │
           ├─ _blockReentrancyCount++  // 再入防止
           │
           ├─ CollectionChanged?.Invoke(this, e)
           │
           └─ _blockReentrancyCount--
```

### データフロー図

```
[入力]                     [処理]                          [出力]

コレクション操作 ───▶ OnCollectionChanged() ───▶ UIの更新
(Add/Remove/etc.)         │                        │
        │                 ▼                        ▼
        │        NotifyCollectionChangedEventArgs  項目の追加/削除
        │        (Action, NewItems, OldItems,     表示更新
        │         NewStartingIndex, OldStartingIndex)
        │                 │
        ▼                 ▼
操作後のコレクション状態   登録済み全ハンドラ
                          へのマルチキャスト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| INotifyCollectionChanged.cs | `src/libraries/System.ObjectModel/src/System/Collections/Specialized/INotifyCollectionChanged.cs` | ソース | インターフェース定義 |
| NotifyCollectionChangedEventArgs.cs | `src/libraries/System.ObjectModel/src/System/Collections/Specialized/NotifyCollectionChangedEventArgs.cs` | ソース | イベント引数クラス |
| ObservableCollection.cs | `src/libraries/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs` | ソース | 主要な実装クラス |
| ReadOnlyObservableCollection.cs | `src/libraries/System.ObjectModel/src/System/Collections/ObjectModel/ReadOnlyObservableCollection.cs` | ソース | 読み取り専用ラッパー |
