# 機能設計書 40-イベント処理

## 概要

本ドキュメントは、F#コアライブラリにおけるイベント処理（Event）機能の機能設計を記述する。Event型はF#における型安全なイベント発行・購読の仕組みを提供し、.NETのデリゲートベースのイベントモデルとの相互運用性を確保しながら、関数型プログラミングスタイルでのイベント処理を可能にする。

### 本機能の処理概要

**業務上の目的・背景**：.NETのイベントモデルはデリゲートベースで実装されているが、F#では関数型プログラミングの観点からイベントを第一級の値として扱いたい。Event型とIEvent<'T>インターフェースはこの要求を満たし、イベントの発行（Trigger）と購読（Add/Subscribe）を型安全に行えるようにする。また、IObservable<'T>を実装することでObservableモジュールとの連携も可能。

**機能の利用シーン**：カスタムコントロールのイベント定義、状態変更の通知、Publisher-Subscriberパターンの実装、UIフレームワークとの統合、非同期イベントの発行など。

**主要な処理内容**：
1. Event<'T>型: 単一引数イベントの発行・購読
2. Event<'Delegate, 'Args>型: カスタムデリゲート対応イベントの発行・購読
3. DelegateEvent<'Delegate>型: 動的引数のデリゲートイベント
4. IEvent<'T>インターフェース: イベント購読のための公開インターフェース
5. IDelegateEvent<'Delegate>インターフェース: デリゲートハンドラの追加・削除

**関連システム・外部連携**：.NETのデリゲートおよびイベントモデルと完全互換。IObservable<'T>を実装しObservableパターンに対応。

**権限による制御**：本機能はライブラリ機能であり、権限による制御は行わない。

## 関連画面

該当なし（コアライブラリ機能であり、画面は持たない）

## 機能種別

イベント処理 / パブリッシュ・サブスクライブ / デリゲート管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| arg | 'T / 'Args | Yes | イベント引数 | - |
| sender | obj | No | イベント送信者（nullの場合あり） | - |
| handler | 'Delegate / Handler<'T> | No | イベントハンドラ | - |
| callback | 'T -> unit | No | コールバック関数 | - |

### 入力データソース

F#プログラム内でのイベント発行呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Publish | IEvent<'Delegate, 'Args> / IEvent<'T> | イベント購読用のインターフェース |
| IDisposable | IDisposable | 購読解除用のディスポーザブル |

### 出力先

イベントハンドラへのコールバック呼び出し。

## 処理フロー

### 処理シーケンス

```
1. Event型の生成
   └─ 内部のmulticastデリゲートを初期化（null）
2. Publishプロパティの公開
   └─ IEvent<'T>インターフェースとして公開
3. ハンドラの追加（Add/AddHandler）
   └─ Delegate.Combineでマルチキャストに追加
4. イベントの発行（Trigger）
   └─ multicastデリゲートを呼び出し
   └─ すべてのハンドラに通知
5. ハンドラの削除（RemoveHandler）
   └─ Delegate.Removeでマルチキャストから削除
```

### フローチャート

```mermaid
flowchart TD
    A[Event<'T>生成] --> B[multicast = null]
    B --> C[Publishプロパティ公開]

    D[AddHandler] --> E[Delegate.Combine]
    E --> F[multicastを更新]

    G[Trigger arg] --> H{multicast != null?}
    H -->|Yes| I[multicast.Invoke]
    H -->|No| J[何もしない]
    I --> K[すべてのハンドラに通知]

    L[RemoveHandler] --> M[Delegate.Remove]
    M --> N[multicastを更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-40-1 | ハンドラ呼び出し順序 | ハンドラはAdd順に呼び出される | Trigger時 |
| BR-40-2 | null安全 | ハンドラがない場合Triggerは何もしない | multicastがnullの場合 |
| BR-40-3 | スレッドセーフ | AddHandler/RemoveHandlerはAtomicに更新 | 並行アクセス時 |
| BR-40-4 | IObservable互換 | SubscribeでIObserverを登録可能 | リアクティブ使用時 |

### 計算ロジック

- Delegate.Combineでハンドラを追加（マルチキャストデリゲート）
- Delegate.Removeでハンドラを削除
- Interlocked.CompareExchangeでアトミックな更新

## データベース操作仕様

該当なし（メモリ上のデータ操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 例外伝播 | ハンドラ例外 | ハンドラ内で例外が発生した場合 | try-catchでラップするか呼び出し元で処理 |

### リトライ仕様

該当なし（イベントは一度のみ発行）

## トランザクション仕様

該当なし（イベント発行は一方向）

## パフォーマンス要件

- AddHandler/RemoveHandler: O(1)（Interlocked操作）
- Trigger: O(n)（ハンドラ数に比例）
- 多引数イベントはリフレクションを使用（若干のオーバーヘッド）

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

特になし（メモリ内イベント処理のみ）

## 備考

- Event<'T>は単一引数のシンプルなイベントに最適
- Event<'Delegate, 'Args>はカスタムデリゲート（sender付き等）に対応
- DelegateEventは動的な引数配列をサポート（相互運用用）
- 多引数のイベント（2〜6引数）はタプル化して処理

---

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

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

### 推奨読解順序

#### Step 1: アトミック更新機構を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.fs | `src/FSharp.Core/event.fs` | Atomicモジュール（12-26行目） |

**読解のコツ**:
- `setWith`関数はInterlocked.CompareExchangeを使用してスレッドセーフな更新を行う
- while not exchangedループで楽観的ロックを実現

#### Step 2: DelegateEvent型を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | event.fs | `src/FSharp.Core/event.fs` | DelegateEvent<'Delegate>型（27-43行目） |

**主要処理フロー**:
1. **29行目**: `multicast`フィールド - マルチキャストデリゲートを保持
2. **31-34行目**: `Trigger`メソッド - DynamicInvokeで動的呼び出し
3. **36-42行目**: `Publish`プロパティ - IDelegateEvent<'Delegate>として公開

#### Step 3: Event<'Delegate, 'Args>型を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | event.fs | `src/FSharp.Core/event.fs` | Event<'Delegate, 'Args>型（79-163行目） |

**主要処理フロー**:
1. **84行目**: `multicast`フィールド - 型付きマルチキャストデリゲート
2. **86-96行目**: 静的初期化 - リフレクションでInvokeメソッド情報を取得
3. **99-103行目**: `invoker` - 1引数の場合の高速パス（EventWrapper）
4. **123-139行目**: `Trigger`メソッド - invokerまたはDynamicInvokeで呼び出し
5. **141-163行目**: `Publish`プロパティ - IEvent<'Delegate, 'Args>として公開

#### Step 4: Event<'T>型を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | event.fs | `src/FSharp.Core/event.fs` | Event<'T>型（165-195行目） |

**主要処理フロー**:
1. **167行目**: `multicast`フィールド - Handler<'T>型のマルチキャスト
2. **170-173行目**: `Trigger`メソッド - シンプルなInvoke呼び出し
3. **175-194行目**: `Publish`プロパティ - IEvent<'T>として公開
4. **185-193行目**: `Subscribe`メソッド - IObservable<'T>の実装

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

```
ユーザーコード
    │
    ├─ let event = Event<string>()
    │      └─ multicast = null
    │
    ├─ event.Publish.Add(fun s -> printfn "%s" s)
    │      └─ IEvent.AddHandler
    │             └─ Atomic.setWith (Delegate.Combine)
    │                    └─ multicast更新
    │
    ├─ event.Trigger("Hello")
    │      └─ multicast.Invoke(null, "Hello")
    │             └─ 全ハンドラ呼び出し
    │
    └─ event.Publish.Subscribe(observer)
           └─ Handler<_>(fun _ args -> observer.OnNext(args))
                  └─ AddHandler
                         └─ IDisposable（RemoveHandler用）を返却
```

### データフロー図

```
[発行側]                      [Event<'T>]                       [購読側]

                            ┌─────────────────┐
Event<'T>()  ───────────▶   │ multicast: null │
                            └─────────────────┘
                                    │
                                    ▼
Publish.Add(handler) ───────────▶ Delegate.Combine
                                    │
                            ┌───────▼─────────┐
                            │ multicast: h1   │
                            └─────────────────┘
                                    │
Publish.Add(handler2) ──────────▶ Delegate.Combine
                                    │
                            ┌───────▼─────────┐
                            │ multicast: h1+h2│
                            └─────────────────┘
                                    │
Trigger(arg) ───────────────────────┼──────────────────▶ h1(arg)
                                    └──────────────────▶ h2(arg)
```

### EventDelegee型について

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| - | event.fs | `src/FSharp.Core/event.fs` | EventDelegee<'Args>型（45-75行目） |

**読解のコツ**:
- IObservable.Subscribeで使用される内部ヘルパー型
- 多引数イベント（2〜6引数）をタプルとしてOnNextに渡す
- `makeTuple`で引数配列からタプルを構築

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.fs | `src/FSharp.Core/event.fs` | ソース | Event型の実装 |
| event.fsi | `src/FSharp.Core/event.fsi` | シグネチャ | Event型のシグネチャ定義 |
| observable.fs | `src/FSharp.Core/observable.fs` | ソース | Observableモジュール（連携） |
