# 機能設計書 37-リフレクション

## 概要

本ドキュメントは、F#コアライブラリにおけるリフレクション（Reflection）機能の機能設計を記述する。F#リフレクション機能は、F#固有の型（レコード、判別共用体、タプル、関数型など）のメタデータを実行時に検査・操作するための機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：.NETの標準リフレクションAPIはF#固有の型構造（判別共用体、レコードなど）を適切に扱うことができない。F#リフレクション機能は、これらのF#特有の型に対して型安全で効率的なリフレクション操作を提供し、シリアライゼーション、ORM、依存性注入、テストフレームワークなどの実装を可能にする。

**機能の利用シーン**：JSONシリアライゼーション（判別共用体のケース名取得）、ORMマッピング（レコードフィールドの自動マッピング）、依存性注入コンテナの実装、単体テストフレームワーク（モック生成）、汎用的なデータ変換ライブラリなど。

**主要な処理内容**：
1. FSharpType モジュール: 型の検査（IsRecord、IsUnion、IsTuple、IsFunction等）
2. FSharpType モジュール: 型情報の取得（GetRecordFields、GetUnionCases、GetTupleElements等）
3. FSharpValue モジュール: 値の構築（MakeRecord、MakeUnion、MakeTuple等）
4. FSharpValue モジュール: 値の分解（GetRecordFields、GetUnionFields、GetTupleFields等）
5. UnionCaseInfo型: 判別共用体ケースのメタデータ表現

**関連システム・外部連携**：.NETのSystem.Reflection APIと連携。F#コンパイラが生成するメタデータ属性（CompilationMappingAttribute等）を読み取る。

**権限による制御**：本機能はライブラリ関数群であり、権限による制御は行わない。ただし、非パブリックメンバーへのアクセスにはBindingFlags.NonPublicの指定が必要。

## 関連画面

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

## 機能種別

リフレクション / 型検査 / 値操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | Type | Yes | 検査対象の型 | - |
| obj | obj | No | 操作対象のオブジェクト | - |
| unionCase | UnionCaseInfo | No | 判別共用体ケース情報 | - |
| values | obj array | No | 構築時のフィールド値 | - |
| bindingFlags | BindingFlags | No | メンバーアクセスフラグ | - |

### 入力データソース

F#プログラム内で生成される型情報（typeof<'T>）またはオブジェクトインスタンス。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 結果 | bool / PropertyInfo[] / UnionCaseInfo[] / Type[] / obj | 各関数に応じた戻り値 |

### 出力先

関数の戻り値としてプログラムに返却。

## 処理フロー

### 処理シーケンス

```
1. 型情報の取得
   └─ typeof<'T>またはobj.GetType()
2. F#型の判定
   └─ CompilationMappingAttributeを検査
   └─ SourceConstructFlagsを確認
3. メタデータの取得
   └─ プロパティ/フィールド/メソッド情報を収集
4. 値の操作
   └─ 構築: コンストラクタまたはファクトリメソッドを呼び出し
   └─ 分解: プロパティ/フィールドアクセス
```

### フローチャート

```mermaid
flowchart TD
    A[型情報を取得] --> B{型種別を判定}
    B -->|Record| C[GetRecordFields]
    C --> D[PropertyInfo配列を返却]
    B -->|Union| E[GetUnionCases]
    E --> F[UnionCaseInfo配列を返却]
    B -->|Tuple| G[GetTupleElements]
    G --> H[Type配列を返却]
    B -->|Function| I[GetFunctionElements]
    I --> J[domain/rangeのタプルを返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-1 | F#型判定 | CompilationMappingAttributeの有無でF#型を識別 | 型判定時 |
| BR-37-2 | 非パブリックアクセス | BindingFlags.NonPublicを指定しない限り非パブリックメンバーは取得不可 | メタデータ取得時 |
| BR-37-3 | 事前計算 | PreComputeXxx関数で高速なアクセサを事前計算可能 | 高頻度アクセス時 |
| BR-37-4 | 例外 | F#型でない型に対してF#リフレクション関数を呼ぶとArgumentException | 型不一致時 |

### 計算ロジック

- 型判定: CompilationMappingAttributeのSourceConstructFlagsを確認
- 値構築: リフレクションまたは事前計算されたデリゲートを使用
- 値分解: プロパティアクセサまたは事前計算されたデリゲートを使用

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ArgumentException | 実行時例外 | F#型でない型に対してF#リフレクション関数を呼んだ場合 | IsRecord等で事前チェック |
| TargetInvocationException | 実行時例外 | MakeRecord等でコンストラクタが例外を投げた場合 | InnerExceptionを確認 |

### リトライ仕様

該当なし（単純な同期操作のため）

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

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

## パフォーマンス要件

- 初回の型検査は遅い（リフレクション使用）
- PreComputeXxx関数を使用することで繰り返しアクセスを高速化
- 型情報はキャッシュされる

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

- 非パブリックメンバーへのアクセスには適切な権限が必要
- リフレクションを通じた値の改変は型安全性を損なう可能性がある

## 備考

- F#リフレクションは.NETリフレクションの上に構築されている
- 判別共用体のケース名は実行時に取得可能（シリアライゼーションに有用）
- 匿名レコードはF#リフレクションでサポートされる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reflect.fs | `src/FSharp.Core/reflect.fs` | SourceConstructFlagsと関連属性（1-50行目付近） |

**読解のコツ**:
- `SourceConstructFlags`列挙体はF#型の種類を識別するフラグ
- `CompilationMappingAttribute`はF#コンパイラが付与するメタデータ属性

#### Step 2: FSharpTypeモジュールを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reflect.fs | `src/FSharp.Core/reflect.fs` | FSharpTypeモジュールの型判定関数群 |

**主要処理フロー**:
1. `IsRecord`: レコード型かどうかを判定
2. `IsUnion`: 判別共用体型かどうかを判定
3. `IsTuple`: タプル型かどうかを判定
4. `IsFunction`: 関数型かどうかを判定
5. `GetRecordFields`: レコードのフィールド情報を取得
6. `GetUnionCases`: 判別共用体のケース情報を取得

#### Step 3: FSharpValueモジュールを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | reflect.fs | `src/FSharp.Core/reflect.fs` | FSharpValueモジュールの値操作関数群 |

**主要処理フロー**:
- `MakeRecord`: レコード値の構築
- `MakeUnion`: 判別共用体値の構築
- `MakeTuple`: タプル値の構築
- `GetRecordFields`: レコード値のフィールド値取得
- `GetUnionFields`: 判別共用体値のケースとフィールド値取得
- `GetTupleFields`: タプル値の要素取得

#### Step 4: 事前計算関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | reflect.fs | `src/FSharp.Core/reflect.fs` | PreCompute系関数群 |

**主要処理フロー**:
- `PreComputeRecordConstructor`: レコードコンストラクタを事前計算
- `PreComputeUnionConstructor`: 判別共用体コンストラクタを事前計算
- `PreComputeTupleConstructor`: タプルコンストラクタを事前計算
- `PreComputeRecordReader`: レコードリーダーを事前計算
- `PreComputeUnionReader`: 判別共用体リーダーを事前計算

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

```
ユーザーコード
    │
    ├─ FSharpType.IsRecord(typeof<MyRecord>)
    │      └─ CompilationMappingAttributeを検査
    │             └─ SourceConstructFlags.RecordTypeを確認
    │
    ├─ FSharpType.GetRecordFields(typeof<MyRecord>)
    │      └─ プロパティ情報をリフレクションで取得
    │             └─ PropertyInfo[]を返却
    │
    ├─ FSharpValue.MakeRecord(typeof<MyRecord>, values)
    │      └─ コンストラクタをリフレクションで呼び出し
    │             └─ obj（レコードインスタンス）を返却
    │
    └─ FSharpValue.PreComputeRecordConstructor(typeof<MyRecord>)
           └─ Func<obj[], obj>デリゲートを生成
                  └─ 高速な繰り返し構築に使用
```

### データフロー図

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

Type ─────────────────▶ CompilationMappingAttribute ───▶ bool (IsXxx)
                              │
                              └──▶ SourceConstructFlags確認

Type ─────────────────▶ Reflection.GetProperties ──────▶ PropertyInfo[]
                              │                           (GetRecordFields)
                              └──▶ フィルタリング

Type + obj[] ─────────▶ ConstructorInfo.Invoke ────────▶ obj (MakeRecord)
                              │
                              └──▶ インスタンス生成

obj ──────────────────▶ PropertyInfo.GetValue ─────────▶ obj[] (GetRecordFields)
                              │
                              └──▶ 各フィールド値を取得
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reflect.fs | `src/FSharp.Core/reflect.fs` | ソース | リフレクション機能の実装 |
| reflect.fsi | `src/FSharp.Core/reflect.fsi` | シグネチャ | リフレクション機能のシグネチャ定義 |
