夕暮ログ

C#やJavascript、最近はAndroidなんかも好きなtinqのブログ。「夕暮れログ」

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ジェネリックスなEnumのユーティリティ

C#(.NET Framework)ではSystem.Enumに列挙体を操作するツールがいくつかあります。
System.Enum クラス

さて、その中の多くのメソッドがTypeを引数にとります。
これは実はジェネリックスを使えばもっとわかりやすく、簡単にかけそうなものばかりです。
しかし、実際によくよく調べてみると、そうでもなかったりします・・・

たとえばParseメソッドを見てみます。これは引数に列挙体のTypeを指定してあげないといけません。
変換後はobjectで帰ってくるので、キャストをしてあげる必要があります。
MSDNのサンプルを例に出します。
Enum.Parse メソッド
完全なコードはそちらをご覧ください。
//ジェネリックじゃない
Colors colorValue = Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString);
//ジェネリックに対応していれば
Colors colorValue = Enum.Parse<Colors>(colorString);
このようにジェネリックスに対応していればキャストが必要なくなり、ソースは短くなります。
内部でどのような処理をしているのかわかりませんが、boxingが減らせる可能性もありそうな気がします。
しかし、TryParseというメソッドが.NET Framework4で追加され、そちらはジェネリックで使えます。
outでとるためあまり使いやすくはないですが、基本的にParseで変換するときに文字列が正しいかチェックしなくていい場合は少ないので、こちらを使え、ということかもしれません。

同じようにジェネリックだとキャストが要らなくなるものにToObjectメソッドがあります。
しかし、これも基本的に数値から列挙体に直にキャストしてしまうことができるため、あまり使いません。
DayOfWeek day = (DayOfWeek)Enum.ToObject(typeof(DayOfWeek), 1);
DayOfWeek day2 = (DayOfWeek)1;
じゃあ紛らわしいから、普通にキャストでいいじゃん!
むしろ、どんなときに使うんだよ!っと一瞬思いましたが、そういえば、ここら辺で使った記憶が・・・
列挙体をデバッグするためのビジュアライザ - 夕暮ログ
そのときには、列挙体を汎用的に扱うために具体的な型は出さずEnumとして処理を行う必要があり、その過程で使ったような気がします。
具体的な列挙体名は出てこないので直接キャストすることはできないのですが、TypeはGetTypeから入手可能で、さらにその正体不明の列挙体のインスタンスを作らなければならないというきわめてまれな状況になっていたと思います。もちろん、戻ってくる型は静的には決まらないので、objectかEnumで受け取る必要があります。
このように型が決められない、きわめてまれな状況専用のメソッドなのかもしれません。それならジェネリックスはできません。

(ちなみに、そのビジュアライザはソースつきで公開しているので、興味があったら見てってください・・・)

続いて、GetNameメソッド
こいつはMSDNのサンプルを見るとどうやら列挙体ではなく数値を渡して文字列に変換することが目的のようです。
確かに、列挙体のオブジェクトならToStringを呼べばいいだけ。ジェネリックスは必要なさそうです。

最後に、Formatメソッド
これはサンプルでも列挙体を渡していて、ジェネリックにしたら推論も聞いてすごく短くかける!
DayOfWeek day = DayOfWeek.Saturday;
//ジェネリックスなし
Console.WriteLine(Enum.Format(typeof(DayOfWeek), day, "G"));
//ジェネリックスあり
Console.WriteLine(Enum.Format(day, "G"));
やった!

・・・・・・で、いつ使うの?このメソッド。
ToStringやGetNameと等価のGを除くと、ほとんどは値を数値として表示するために使うようですが、表示する機会ってほとんどありません。
Enumを汎用的に扱ってビジュアライザでも作るときぐらいしか・・・
ジェネリックス、いらなさそうだね。うん。

不要っぽいですが、せっかく書いてしまったので、各メソッドのEnum対応版です。

public class EnumUtils
{
public static string GetName<T>(T value)
where T : struct , IComparable, IFormattable, IConvertible
{
return Enum.GetName(typeof(T), value);
}

public static string Format<T>(T value, string format)
where T : struct , IComparable, IFormattable, IConvertible
{
return Enum.Format(typeof(T), value, format);
}

public static T Parse<T>(string value)
where T : struct , IComparable, IFormattable, IConvertible
{
return Parse<T>( value, false);
}

public static T Parse<T>(string value, bool ignoreCase)
where T : struct , IComparable, IFormattable, IConvertible
{
return (T)Enum.Parse(typeof(T), value, false);
}

public static T ToObject<T>(object value)
where T : struct , IComparable, IFormattable, IConvertible
{
return (T)Enum.ToObject(typeof(T), value);
}
}

関連記事

コメント

ここをクリックしてコメントを投稿

非公開コメント

トラックバック

http://tinqwill.blog59.fc2.com/tb.php/97-04c24e9d

« next  ホーム  prev »

プロフィール

tinq tinq(もしくはTinqWill)

Sky  For   Every 改装予定

プログラミングお勉強中の高校生。月一くらいは更新したい

最新記事

カテゴリ

月別アーカイブ

検索フォーム

最新コメント

リンク

最新トラックバック

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。