[C#][dynamic] 列挙型 (enum) の列挙子の動的な取得など

今回は、列挙型 (enum) の列挙子の取得などについて。

■ 列挙型 (enum) の列挙子を動的なメソッド呼び出しの引数で渡したい

例えば、次のようなクラス ライブラリー (ClassLibrary.dll) があるとする。

// クラス ライブラリー側: ClassLibrary.dll
namespace ClassLibrary
{
// 列挙型 (enum)
public enum ItemKind
{
Book, Toy, Stationary
}
// クラス
public class Item
{
// アイテムの種類 (型は列挙型の ItemKind)
readonly ItemKind itemType;
// コンストラクター (引数でアイテムの種類を指定)
public Item(ItemKind itemType)
{ this.itemType = itemType; }
}
}

そして、別のプロジェクトで、このクラス ライブラリーを動的に読み込んで使いたいとする。

例.

// クラス ライブラリーを動的に利用する側: Xxx.exe
using System;
using System.Reflection;
class Program
{
static void Main()
{
// アセンブリ名を使ってクラス ライブラリーを動的に読み込み
var assembly = Assembly.Load("ClassLibrary");
// アセンブリ内のクラスの型情報を取得
var itemType = assembly.GetType("ClassLibrary.Item");
// ... 途中省略 ...
}
}

ここで次のように、型情報 itemType を使って、インスタンスを生成させようとしてみる。

// ... 途中省略 ...
// アセンブリ名を使ってクラス ライブラリーを動的に読み込み
var assembly = Assembly.Load("ClassLibrary");
// アセンブリ内のクラスの型情報を取得
var itemType = assembly.GetType("ClassLibrary.Item");
// クラスの型情報を使って、クラスのインスタンスを生成
dynamic item = Activator.CreateInstance(itemType, 0 /* ClassLibrary.ItemKind.Book の値 */);
// ... 途中省略 ...

これは次のように、実行時エラーになる。
コンストラクターの引数の型が合っていないからだ。

実行時エラー その1

勿論、object にキャストしても実行時エラーの儘だ。

実行時エラー その2

だが、クラス ライブラリーを動的に読み込みたい訳なので、ClassLibrary.ItemKind.Book と書く訳にもいかない。

// ... 途中省略 ...
// クラスの型情報を使って、クラスのインスタンスを生成
dynamic item = Activator.CreateInstance(itemType, ClassLibrary.ItemKind.Book); // コンパイル エラー
// ... 途中省略 ...

こういう場合はどうすれば良いだろうか?

これは、次のように、列挙型 (enum) の型情報も取得して、そこから ClassLibrary.ItemKind.Book を生成してやれば良い。

// ... 途中省略 ...
// アセンブリ内の列挙型 (enum) の型情報をアセンブリから取得
var itemKindType     = assembly.GetType("ClassLibrary.ItemKind");
// enum の列挙オブジェクト ClassLibrary.ItemKind.Book を生成
var itemKindTypeBook = Enum.Parse(itemKindType, "Book");
// クラスの型情報を使って、クラスのインスタンスを生成
dynamic item = Activator.CreateInstance(itemType, itemKindTypeBook);
// ... 途中省略 ...

Enum.Parse メソッドを使って enum の列挙子名から列挙オブジェクトを生成するのがポイントだ。

■ 列挙型 (enum) の列挙子の名称を取得

列挙型 (enum) の型情報から全ての列挙子の名称を取得することもできる。

例えば、列挙型 (enum) ClassLibrary.ItemKind の全ての列挙子の名称を取得するには次のようにすれば良い。

// ... 途中省略 ...
// 列挙型 (enum) の全ての列挙子の名称を取得
string[] itemKindTypeNames = Enum.GetNames(typeof(ClassLibrary.ItemKind));
// ... 途中省略 ...

列挙子の名称が配列で得られる。即ち、ここから列挙子の数を取得することができることになる。

// ... 途中省略 ...
// 列挙型 (enum) の列挙子の数を取得
int itemKindTypeLength = Enum.GetNames(typeof(ClassLibrary.ItemKind)).Length;
// ... 途中省略 ...

Enum.GetTypes メソッドで、全ての列挙子オブジェクトを配列 (Array) で取得することもできるので、次のようにしても良い。

// ... 途中省略 ...
// 列挙型 (enum) の列挙子の数を取得
int itemKindTypeLength = Enum.GetTypes(typeof(ClassLibrary.ItemKind)).Length;
// ... 途中省略 ...