# 通知設計書 9-INotifyComposablePartCatalogChanged.Changing

## 概要

本ドキュメントは、.NET Runtimeにおける`INotifyComposablePartCatalogChanged.Changing`イベント通知の設計を記述する。このイベントは、MEF（Managed Extensibility Framework）のカタログ内容が変更される**直前**に発生するイベントである。

### 本通知の処理概要

`INotifyComposablePartCatalogChanged.Changing`イベントは、`ComposablePartCatalog`の内容が変更される直前にリスナーに通知するためのイベントである。`Changed`イベントと対になり、変更前の状態での処理や変更のバリデーションを可能にする。

**業務上の目的・背景**：MEFのカタログ変更は、アプリケーション全体のコンポジションに影響を与える可能性がある。`Changing`イベントでは、`AtomicComposition`オブジェクトを通じてトランザクション的な変更管理が可能になる。リスナーは変更をプレビューし、必要に応じてロールバック用のアクションを登録したり、例外をスローして変更をキャンセルしたりできる。

**通知の送信タイミング**：カタログにパーツ定義が追加または削除される直前に発火する。`Changing`イベントが先に発火し、リスナーが例外をスローしなければ、実際の変更が適用され、その後`Changed`イベントが発火する。

**通知の受信者**：`Changing`イベントを購読しているすべてのイベントハンドラが受信者となる。一般的には`CompositionContainer`やカタログを管理するコードがリスナーとなる。

**通知内容の概要**：`ComposablePartCatalogChangeEventArgs`オブジェクトを通じて、追加予定のパーツ定義（`AddedDefinitions`）、削除予定のパーツ定義（`RemovedDefinitions`）、およびトランザクションコンテキスト（`AtomicComposition`）が通知される。

**期待されるアクション**：受信者は変更内容を検証し、`AtomicComposition`にロールバックアクションを登録したり、必要に応じて例外をスローして変更をキャンセルしたりする。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高（変更キャンセル機能があるため） |
| リトライ | なし（同期イベント） |

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

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

## 通知テンプレート

### インターフェース定義

```csharp
namespace System.ComponentModel.Composition.Hosting
{
    public interface INotifyComposablePartCatalogChanged
    {
        event EventHandler<ComposablePartCatalogChangeEventArgs>? Changed;
        event EventHandler<ComposablePartCatalogChangeEventArgs>? Changing;
    }
}
```

### ComposablePartCatalogChangeEventArgs（Changingでの使用）

```csharp
public class ComposablePartCatalogChangeEventArgs : EventArgs
{
    public IEnumerable<ComposablePartDefinition> AddedDefinitions { get; }
    public IEnumerable<ComposablePartDefinition> RemovedDefinitions { get; }
    public AtomicComposition? AtomicComposition { get; }  // Changingでは非null
}
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| AddedDefinitions | 追加予定のパーツ定義のコレクション | カタログ操作 | Yes（空でも可） |
| RemovedDefinitions | 削除予定のパーツ定義のコレクション | カタログ操作 | Yes（空でも可） |
| AtomicComposition | アトミック操作のコンテキスト（非null） | トランザクション管理 | Yes（通常） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| プログラム実行 | カタログへのパーツ追加前 | 追加が開始された場合 | AddedDefinitionsに追加予定パーツが含まれる |
| プログラム実行 | カタログからのパーツ削除前 | 削除が開始された場合 | RemovedDefinitionsに削除予定パーツが含まれる |
| プログラム実行 | DirectoryCatalogのリフレッシュ前 | ファイル変更を検出した場合 | 追加・削除両方が含まれる可能性あり |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | 変更操作時は常に発火 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[カタログ変更操作] --> B[AtomicComposition作成/取得]
    B --> C[OnChangingメソッド呼び出し]
    C --> D{Changingイベントハンドラあり?}
    D -->|No| E[カタログ内容を更新]
    D -->|Yes| F[Changingイベント発火]
    F --> G{例外発生?}
    G -->|Yes| H[変更をキャンセル/ロールバック]
    G -->|No| I{AtomicCompositionにアクション登録あり?}
    I -->|Yes| J[完了時にアクション実行をスケジュール]
    I -->|No| E
    J --> E
    E --> K[OnChangedメソッド呼び出し]
    K --> L[Changedイベント発火]
    L --> M[終了]
    H --> M
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ChangeRejectedException | リスナーが変更を拒否した場合 | 変更がキャンセルされる |
| ObjectDisposedException | カタログがDisposeされた場合 | Disposeの前にイベントハンドラを解除 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

- パーツ定義に含まれる型情報が機密である場合は注意が必要
- 例外をスローして変更をキャンセルする場合、DoS攻撃に悪用されないよう注意
- 外部からのプラグイン読み込み時は事前検証を推奨

## 備考

- `System.ComponentModel.Composition.Hosting`名前空間に定義
- `Changed`イベントと対になり、変更のライフサイクルを形成
- `AtomicComposition`を使用してトランザクション的な変更管理が可能
- 例外をスローすると変更がキャンセルされる
- `INotifyPropertyChanging`との類似性：変更前通知のパターン

---

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

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

### 推奨読解順序

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

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

**読解のコツ**: `Changed`と`Changing`の2つのイベントがペアで定義されていることを確認。

**主要処理フロー**:
1. **行9**: インターフェース定義
2. **行11**: `Changed`イベント（変更後）
3. **行12**: `Changing`イベント（変更前）

#### Step 2: イベント引数とAtomicCompositionを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ComposablePartCatalogChangeEventArgs.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/ComposablePartCatalogChangeEventArgs.cs` | AtomicCompositionプロパティの役割（行86-98） |

**主要処理フロー**:
- **行86-97**: XMLドキュメント - AtomicCompositionの用途説明
- **行98**: `AtomicComposition`プロパティ

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AggregateCatalog.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AggregateCatalog.cs` | OnChangingメソッドの実装（行215-218） |

**主要処理フロー**:
- **行88-98**: `Changing`イベントの定義
- **行215-218**: `OnChanging`メソッド - _catalogsに委譲

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

```
AggregateCatalog.Catalogs.Add(newCatalog)
    │
    └─ ComposablePartCatalogCollection.Add(catalog)
           │
           ├─ [AtomicCompositionの作成/取得]
           │
           ├─ OnChanging(args)  // args.AtomicComposition != null
           │      │
           │      └─ Changing?.Invoke(sender, args)
           │             │
           │             ├─ [リスナーがAtomicCompositionにアクション登録]
           │             │      atomicComposition.AddCompleteAction(...)
           │             │      atomicComposition.AddRevertAction(...)
           │             │
           │             └─ [リスナーが例外をスロー可能]
           │                    throw new ChangeRejectedException(...)
           │
           ├─ [例外なし: カタログをコレクションに追加]
           │
           └─ OnChanged(args)  // args.AtomicComposition == null
                  │
                  └─ Changed?.Invoke(sender, args)
```

### データフロー図

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

カタログ変更要求 ───▶ AtomicComposition作成 ───▶ トランザクション
(Add/Remove)              │                        コンテキスト
        │                 ▼
        │          OnChanging() ───▶ Changingイベント
        │                 │               │
        │                 │               ▼
        │                 │         リスナーが検証
        │                 │               │
        │                 ▼               ▼
        │         例外なし ──────▶ カタログ更新
        │                               │
        │                               ▼
        │         例外あり ──────▶ 変更キャンセル
        │                               │
        ▼                               ▼
ComposablePartCatalog-          OnChanged() or
ChangeEventArgs                 ロールバック
(AddedDefinitions,
 RemovedDefinitions,
 AtomicComposition)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| INotifyComposablePartCatalogChanged.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/INotifyComposablePartCatalogChanged.cs` | ソース | インターフェース定義 |
| ComposablePartCatalogChangeEventArgs.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/ComposablePartCatalogChangeEventArgs.cs` | ソース | イベント引数クラス |
| AggregateCatalog.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AggregateCatalog.cs` | ソース | 実装例 |
| ComposablePartCatalogCollection.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/ComposablePartCatalogCollection.cs` | ソース | 内部コレクション実装 |
