# 通知設計書 8-INotifyComposablePartCatalogChanged.Changed

## 概要

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

### 本通知の処理概要

`INotifyComposablePartCatalogChanged.Changed`イベントは、`ComposablePartCatalog`の内容が変更された後にリスナーに通知するためのイベントである。MEFはプラグインアーキテクチャを実現するためのフレームワークであり、カタログはエクスポートされたパーツ（コンポーネント）の定義を保持する。

**業務上の目的・背景**：MEFを使用したアプリケーションでは、プラグインの動的な追加・削除が必要なシナリオがある。`INotifyComposablePartCatalogChanged`インターフェースを実装するカタログ（`AggregateCatalog`、`DirectoryCatalog`等）は、内容が変更された際にこのイベントを発火する。これにより、コンポジションコンテナがカタログの変更に対応して再コンポジションを行うことができる。

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

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

**通知内容の概要**：`ComposablePartCatalogChangeEventArgs`オブジェクトを通じて、追加されたパーツ定義（`AddedDefinitions`）と削除されたパーツ定義（`RemovedDefinitions`）が通知される。

**期待されるアクション**：受信者は追加・削除されたパーツ定義に基づいて、コンポジションの更新、キャッシュの無効化、依存関係の再解決などを行う。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

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

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

### ComposablePartCatalogChangeEventArgs

```csharp
public class ComposablePartCatalogChangeEventArgs : EventArgs
{
    public ComposablePartCatalogChangeEventArgs(
        IEnumerable<ComposablePartDefinition> addedDefinitions,
        IEnumerable<ComposablePartDefinition> removedDefinitions,
        AtomicComposition? atomicComposition);

    public IEnumerable<ComposablePartDefinition> AddedDefinitions { get; }
    public IEnumerable<ComposablePartDefinition> RemovedDefinitions { get; }
    public AtomicComposition? AtomicComposition { get; }
}
```

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| AddedDefinitions | 追加されたパーツ定義のコレクション | カタログ操作 | Yes（空でも可） |
| RemovedDefinitions | 削除されたパーツ定義のコレクション | カタログ操作 | Yes（空でも可） |
| AtomicComposition | アトミック操作のコンテキスト（Changedではnull） | N/A | No |

## 送信トリガー・条件

### トリガー一覧

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

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| Changingイベントで例外発生 | 変更がキャンセルされた場合はChangedは発火しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[カタログ変更操作] --> B[OnChangingメソッド呼び出し]
    B --> C[Changingイベント発火]
    C --> D{例外発生?}
    D -->|Yes| E[変更をロールバック]
    D -->|No| F[カタログ内容を更新]
    F --> G[OnChangedメソッド呼び出し]
    G --> H{Changedイベントハンドラあり?}
    H -->|No| I[終了]
    H -->|Yes| J[Changedイベント発火]
    J --> K[各イベントハンドラが実行される]
    K --> I
    E --> I
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ObjectDisposedException | カタログがDisposeされた場合 | Disposeの前にイベントハンドラを解除 |
| 引数null例外 | addedDefinitions/removedDefinitionsがnull | 空のEnumerableを渡す |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし

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

- パーツ定義に含まれる型情報が機密である場合は注意が必要
- MEFは部分信頼シナリオでの使用は非推奨
- 外部からのプラグイン読み込み時はアセンブリの署名検証を推奨

## 備考

- `System.ComponentModel.Composition.Hosting`名前空間に定義
- `AggregateCatalog`、`DirectoryCatalog`、`FilteredCatalog`等がこのインターフェースを実装
- `Changing`イベントは変更前、`Changed`イベントは変更後に発火
- `AtomicComposition`は`Changing`イベントでは非null、`Changed`イベントではnullになることが多い
- スレッドセーフ：カタログの実装による

---

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

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

### 推奨読解順序

#### 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**: `INotifyComposablePartCatalogChanged`インターフェースの定義
2. **行11**: `Changed`イベントの定義
3. **行12**: `Changing`イベントの定義

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ComposablePartCatalogChangeEventArgs.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/ComposablePartCatalogChangeEventArgs.cs` | イベント引数クラス（行16-99） |

**主要処理フロー**:
- **行41-50**: コンストラクタ - addedDefinitions, removedDefinitions, atomicCompositionを設定
- **行59-66**: `AddedDefinitions`プロパティ
- **行76-83**: `RemovedDefinitions`プロパティ
- **行98**: `AtomicComposition`プロパティ

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AggregateCatalog.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AggregateCatalog.cs` | Changed/Changingイベントの実装（行73-98, 205-218） |

**主要処理フロー**:
- **行73-83**: `Changed`イベントの定義（内部コレクションに委譲）
- **行88-98**: `Changing`イベントの定義（内部コレクションに委譲）
- **行205-208**: `OnChanged`メソッド
- **行215-218**: `OnChanging`メソッド

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

```
AggregateCatalog.Catalogs.Add(newCatalog)
    │
    └─ ComposablePartCatalogCollection.Add(catalog)
           │
           ├─ OnChanging(args)
           │      │
           │      └─ Changing?.Invoke(sender, args)
           │             │
           │             └─ [リスナーがAtomicCompositionで変更を記録]
           │
           ├─ [カタログをコレクションに追加]
           │
           └─ OnChanged(args)
                  │
                  └─ Changed?.Invoke(sender, args)
                         │
                         └─ [リスナーがコンポジションを更新]
```

### データフロー図

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

カタログ変更操作 ───▶ OnChanging() ───▶ Changingイベント
(Add/Remove)              │                    │
        │                 ▼                    ▼
        │         AtomicComposition      リスナーが変更を
        │         でトランザクション管理   検証/記録
        │                 │
        │                 ▼
        │         カタログ内容を更新
        │                 │
        │                 ▼
        │          OnChanged() ───▶ Changedイベント
        │                                │
        ▼                                ▼
ComposablePartCatalog-          リスナーが再コンポジション
ChangeEventArgs                 を実行
(AddedDefinitions,
 RemovedDefinitions)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| 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` | ソース | 実装例 |
| DirectoryCatalog.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/DirectoryCatalog.cs` | ソース | 実装例（ディレクトリ監視） |
| FilteredCatalog.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/FilteredCatalog.cs` | ソース | 実装例（フィルタリング） |
| CatalogExportProvider.cs | `src/libraries/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/CatalogExportProvider.cs` | ソース | イベント購読者の例 |
