# 通知設計書 1-INotifyPropertyChanged.PropertyChanged

## 概要

本ドキュメントは、.NET Runtimeにおける`INotifyPropertyChanged.PropertyChanged`イベント通知の設計を記述する。このイベントは、オブジェクトのプロパティが変更された際にリスナーに通知を行うための標準的なメカニズムを提供する。

### 本通知の処理概要

`INotifyPropertyChanged.PropertyChanged`イベントは、オブジェクトのプロパティ値が変更されたことを外部のリスナーに通知するためのイベントである。主にMVVM（Model-View-ViewModel）パターンにおけるデータバインディングで使用され、UIとビジネスロジックの同期を実現する。

**業務上の目的・背景**：MVVMアーキテクチャにおいて、ViewModelのプロパティが変更された際にViewに自動的に変更を反映させる必要がある。手動でUIを更新するコードを書くことなく、宣言的なデータバインディングを実現するために、このインターフェースが設計された。WPF、UWP、Xamarin、MAUIなどのUIフレームワークで広く使用される。

**通知の送信タイミング**：プロパティのsetterが呼び出され、値が変更された後に発火する。実装者は`PropertyChanged`イベントを手動で発火させるか、ソースジェネレーターやFody等のILウィービングツールを使用して自動発火させる。

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

**通知内容の概要**：`PropertyChangedEventArgs`オブジェクトを通じて、変更されたプロパティの名前（`PropertyName`）が通知される。プロパティ名がnullまたは空文字列の場合は、すべてのプロパティが変更されたことを示す。

**期待されるアクション**：受信者はプロパティ名に基づいて、対応するUI要素の更新、キャッシュの無効化、依存プロパティの再計算などを行う。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（デフォルト）、非同期実装も可能 |
| 優先度 | 中 |
| リトライ | なし（同期イベント） |

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

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

## 通知テンプレート

### イベント引数

| 項目 | 内容 |
|-----|------|
| イベント型 | `PropertyChangedEventHandler` |
| 引数型 | `PropertyChangedEventArgs` |
| sender | イベントを発火したオブジェクト（通常は`this`） |

### PropertyChangedEventArgs

```csharp
public class PropertyChangedEventArgs : EventArgs
{
    public PropertyChangedEventArgs(string? propertyName);
    public virtual string? PropertyName { get; }
}
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| PropertyName | 変更されたプロパティの名前 | 実装クラスのプロパティ名 | No（nullで全プロパティ変更を示す） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| プログラム実行 | プロパティsetterの呼び出し | 値が実際に変更された場合 | 典型的な実装パターン |
| プログラム実行 | メソッドによる状態変更 | 複数プロパティに影響する操作 | 明示的なイベント発火 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 値が同一 | 新しい値が既存の値と等しい場合、イベントを発火しないことが推奨される |
| 初期化中 | オブジェクトの初期化中はイベントを発火しないことがある |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[プロパティsetterの呼び出し] --> B{値が変更されたか?}
    B -->|No| C[終了]
    B -->|Yes| D[プライベートフィールドを更新]
    D --> E[OnPropertyChangedメソッド呼び出し]
    E --> F{PropertyChangedイベントハンドラが登録されているか?}
    F -->|No| C
    F -->|Yes| G[PropertyChangedイベントを発火]
    G --> H[各イベントハンドラが実行される]
    H --> C
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| NullReferenceException | イベントハンドラがnullの状態でInvokeを試みた場合 | null条件演算子（?.）を使用 |
| イベントハンドラ内例外 | 購読者のハンドラ内で例外が発生した場合 | 呼び出し元に伝播（try-catchで囲むことも可能） |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- イベントハンドラへの参照がメモリリークの原因となりうる（弱参照パターンの検討）
- マルチスレッド環境でのイベント発火時はスレッドセーフな実装が必要
- PropertyNameに機密情報を含めないこと

## 備考

- C# 5.0以降では`[CallerMemberName]`属性を使用してプロパティ名を自動取得可能
- .NET Community Toolkitの`ObservableObject`基底クラスで実装が簡素化される
- ソースジェネレーター（`[ObservableProperty]`属性）により定型コードを削減可能

---

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

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

### 推奨読解順序

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

まず、イベント引数とデリゲートの定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PropertyChangedEventArgs.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/PropertyChangedEventArgs.cs` | PropertyNameプロパティの定義とコンストラクタを確認 |

**読解のコツ**: `EventArgs`を継承した単純なデータクラス。`PropertyName`がnullまたは空文字列の場合の意味を理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | INotifyPropertyChanged.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/INotifyPropertyChanged.cs` | インターフェースの定義（行6-9） |

**主要処理フロー**:
1. **行6**: `INotifyPropertyChanged`インターフェースの定義
2. **行8**: `PropertyChanged`イベントの宣言

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ObservableCollection.cs | `src/libraries/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs` | `INotifyPropertyChanged`の実装パターン（行74-78, 163-166, 172） |

**主要処理フロー**:
- **行74-78**: 明示的インターフェース実装でPropertyChangedイベントを公開
- **行163-166**: `OnPropertyChanged`メソッドでイベントを発火
- **行172**: `PropertyChanged`イベントの宣言
- **行240, 245**: ヘルパーメソッドでCountとIndexerの変更を通知

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

```
プロパティsetter（例：ObservableCollection.InsertItem）
    │
    ├─ base.InsertItem(index, item)  // 実際のデータ変更
    │
    ├─ OnCountPropertyChanged()
    │      └─ OnPropertyChanged(EventArgsCache.CountPropertyChanged)
    │             └─ PropertyChanged?.Invoke(this, e)
    │
    └─ OnIndexerPropertyChanged()
           └─ OnPropertyChanged(EventArgsCache.IndexerPropertyChanged)
                  └─ PropertyChanged?.Invoke(this, e)
```

### データフロー図

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

プロパティ値変更 ───▶ OnPropertyChanged(e) ───▶ イベントハンドラ実行
      │                      │                        │
      │                      ▼                        ▼
      │               PropertyChangedEvent      UIの更新
      │                   ?.Invoke()           データの再取得
      │                      │                  依存値の再計算
      ▼                      ▼
PropertyChangedEventArgs   登録済み全ハンドラ
(PropertyName)              へのマルチキャスト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| INotifyPropertyChanged.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/INotifyPropertyChanged.cs` | ソース | インターフェース定義 |
| PropertyChangedEventArgs.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/PropertyChangedEventArgs.cs` | ソース | イベント引数クラス |
| ObservableCollection.cs | `src/libraries/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs` | ソース | 実装例 |
| ExpandoObject.cs | `src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs` | ソース | 実装例（動的オブジェクト） |
| DataRowView.cs | `src/libraries/System.Data.Common/src/System/Data/DataRowView.cs` | ソース | 実装例（データバインディング） |
