# 通知設計書 2-INotifyPropertyChanging.PropertyChanging

## 概要

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

### 本通知の処理概要

`INotifyPropertyChanging.PropertyChanging`イベントは、オブジェクトのプロパティ値が変更される直前に外部のリスナーに通知するためのイベントである。`INotifyPropertyChanged`と対になるインターフェースであり、変更前の状態を記録したり、変更を監視する用途に使用される。

**業務上の目的・背景**：データの変更履歴を追跡する必要がある場合や、Undo/Redo機能を実装する際に、変更前の値を保存する必要がある。`PropertyChanged`イベントでは変更後の通知しか受け取れないため、変更前の値にアクセスするには`PropertyChanging`イベントが必要となる。Entity Framework等のORMでは、変更追跡（Change Tracking）のためにこのインターフェースを使用する。

**通知の送信タイミング**：プロパティのsetterが呼び出され、実際の値変更が行われる**前**に発火する。これにより、リスナーは変更前の状態を取得・保存できる。

**通知の受信者**：`PropertyChanging`イベントを購読しているすべてのイベントハンドラが受信者となる。一般的にはORMの変更追跡システム、Undo/Redoマネージャ、監査ログシステムなどがリスナーとなる。

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

**期待されるアクション**：受信者はプロパティ名に基づいて、現在のプロパティ値を取得・保存し、変更履歴への記録や、Undoスタックへのプッシュなどを行う。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 中 |
| リトライ | なし（同期イベント） |

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

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

## 通知テンプレート

### イベント引数

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

### PropertyChangingEventArgs

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

## テンプレート変数

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

## 送信トリガー・条件

### トリガー一覧

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

### 送信抑止条件

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

## 処理フロー

### 送信フロー

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

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| NullReferenceException | イベントハンドラがnullの状態でInvokeを試みた場合 | null条件演算子（?.）を使用 |
| イベントハンドラ内例外 | 購読者のハンドラ内で例外が発生した場合 | プロパティ変更がキャンセルされる可能性あり |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

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

## 備考

- `INotifyPropertyChanging`は`INotifyPropertyChanged`と対になるインターフェース
- Entity Framework Coreでは、変更追跡の最適化のためにこのインターフェースを活用可能
- .NET Standard 2.0以降およびすべての.NET Core/.NET 5+でサポート
- `PropertyChanging`イベントは変更をキャンセルする機能を持たない（キャンセル可能にするには独自実装が必要）

---

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

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

### 推奨読解順序

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

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

**読解のコツ**: `INotifyPropertyChanged`と対比して理解する。イベント名が`PropertyChanging`（現在進行形）である点に注意。

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

#### Step 2: INotifyPropertyChangedとの比較

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | INotifyPropertyChanged.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/INotifyPropertyChanged.cs` | 対になるインターフェースとの構造比較 |

**読解のコツ**: 両インターフェースの構造が同一であることを確認。違いはイベント名（Changed vs Changing）とセマンティクス（変更後 vs 変更前）のみ。

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

```
プロパティsetter（実装例）
    │
    ├─ OnPropertyChanging(propertyName)  // 変更前に通知
    │      └─ PropertyChanging?.Invoke(this, e)
    │
    ├─ _backingField = newValue  // 実際の値変更
    │
    └─ OnPropertyChanged(propertyName)  // 変更後に通知
           └─ PropertyChanged?.Invoke(this, e)
```

### データフロー図

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

プロパティ値変更要求 ───▶ OnPropertyChanging(e) ───▶ 変更前の値を保存
        │                       │                        │
        │                       ▼                        ▼
        │               PropertyChangingEvent      Undo履歴への追加
        │                   ?.Invoke()              変更追跡の開始
        │                       │
        ▼                       ▼
PropertyChangingEventArgs   登録済み全ハンドラ
(PropertyName)               へのマルチキャスト
        │
        ▼
    実際の値変更
        │
        ▼
   PropertyChanged発火
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| INotifyPropertyChanging.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/INotifyPropertyChanging.cs` | ソース | インターフェース定義 |
| INotifyPropertyChanged.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/INotifyPropertyChanged.cs` | ソース | 対になるインターフェース |
| PropertyChangedEventArgs.cs | `src/libraries/System.ObjectModel/src/System/ComponentModel/PropertyChangedEventArgs.cs` | ソース | 類似のイベント引数（参考） |
