Quantcast
Channel: いげ太の日記
Viewing all articles
Browse latest Browse all 26

enum を Dictionary に変換

$
0
0

NOTE: この記事は、当初、ココログの「いげ太のブログ」で公開していたものです。

列挙型の列挙子を列挙したいというのは割とよくある話で、列挙子の名前と値を辞書として取り出すメソッド(関数)を作っておくと便利です。

at C#

現行最新版の C# 3.0 で。型パラメータに列挙型(enum)とその基になる型(underlying type)を指定して IDictionary を返す、静的メソッドを定義します。

using System;
using System.Collections.Generic;

static class EnumEx
{
public static IDictionary<string, TValue> EnumToDictionary<TEnum, TValue>()
where TEnum : struct, IComparable, IFormattable, IConvertible
where TValue : struct
{
var etyp = typeof(TEnum);
if (!etyp.IsEnum)
throw new Exception("TEnum is not enum.");
var vtyp = typeof(TValue);
if (!vtyp.Equals(Enum.GetUnderlyingType(etyp)))
throw new Exception("TValue is not underlying type of TEnum.");

var dic = new Dictionary<string, TValue>();
foreach (TValue val in Enum.GetValues(etyp))
dic.Add(Enum.GetName(etyp, val), val);
return dic;
}
}

C# では、型パラメータの制約に enum を指定することも(コンパイラ エラー CS1031: 型が必要です。)、System.Enum を指定することも(コンパイラ エラー CS0702: 制約は特殊クラス 'System.Enum'にはなれません。)できません。よって、TEnum の型が enum であるかどうか、また TValue が TEnum の基になる型であるかどうかを、静的にチェックすることはできません。ここでは、ある程度それっぽい型であることを静的に判断しておいて、最後は if 文と例外にゆだねています。

使い方は以下の通り。

enum CardSuit { Spades, Hearts, Diamonds, Clubs }

class Program
{
static void Main(string[] args)
{
foreach (var pair in EnumEx.EnumToDictionary<CardSuit, int>())
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
}

at F#

Visual Studio 2010 から搭載される F# でも書いてみます。

module Enum =
open System

let enumdict<'T, 'U when 'T : enum<'U>> =
let t = typeof<'T>
dict( Enum.GetValues(t) |> Seq.cast<'U> |> Seq.zip (Enum.GetNames(t)) )

F# では 列挙型制約(Enumeration Type Constraint)が使えます。'T が enum であり、かつ、'U が 'T の基になる型であることは、コンパイル時に保証されます。

使い方は以下の通り。

type cardsuit = Spades = 0 | Hearts = 1 | Diamonds = 2 | Clubs = 3

module Program =
open Enum

do enumdict<cardsuit, _>
|> Seq.iter (fun (KeyValue(k,v)) -> printfn "%s: %d" k v)

enumdict<cardsuit, int> とする必要はありません。コンパイラは制約を忘れたりしません。'T さえわかれば、制約によって 'U は自明です。ワイルドカード(プレースホルダ)を置いておけば、型推論が cardsuit の基になる型 'U は int であると導き出してくれます。

Conclusion

なんで C# には enum 制約ないんだろ。

関連記事


Viewing all articles
Browse latest Browse all 26

Trending Articles