文字列からの変換
文字列を数値型とか enum 型とかに変換する場合、Parse()
とか TryParse()
を使うかと思います。
Parse()
は、成功すれば変換された値が返ってくる点は楽なのですが、失敗したときに例外を吐くので少々扱いにくいです。
一方、TryParse()
のシグネチャは bool TryParse(string s, out T v)
となっています。返り値は解釈成功・失敗を表し、変換された値は v
に入ります。変数 v
を事前に宣言する1面倒くささはありますが、失敗したときの処理は簡単です。
enum 型への変換
enum 型には、bool Enum.TryParse<TEnum>(string s, out TEnum e)
が使えます。
名前からでも数字からでも TEnum
型に変換できます。
enum Weekday {
Sunday = 0,
Monday = 1,
Tuesday = 2,
:
Saturday = 6
}
Weekday wd;
Enum.TryParse("2", out wd); // true, wd = Weekday.Tuesday
Enum.TryParse("Friday", out wd ); // true, wd = Weekday.Friday
Enum.TryParse("April", out wd); // false, wd = ?
ところが、数字からの変換が曲者で、enum 型で定義していない値でも変換に成功したことにして out
の変数に入れてしまいます。
Enum.TryParse("100", out wd); // true, wd = 100
enum 型への安全な変換
ある値が enum 型で定義されているか検証するには、Enum.IsDefined()
を使います。これを TryParse()
と組み合わせれば、安全な変換が実現できます。
static class EnumExt
{
static bool TryParse(string s, out Weekday wd)
{
return Enum.TryParse(s, out wd) && Enum.IsDefined(typeof(Weekday), wd);
}
}
EnumExt.TryParse("100", out wd); // false, wd = 100
任意の enum 型に対応するため、ジェネリック化します。
型パラメータ TEnum
は enum 型のみを許容するので、'where` 節で制約します。
static class EnumExt
{
static bool TryParse<TEnum>(string s, out TEnum wd) where TEnum : struct
{
return Enum.TryParse(s, out wd) && Enum.IsDefined(typeof(TEnum), wd);
}
}
Weekday wd;
EnumExt.TryParse("Thursday", out wd); // true, wd = Weekday.Thursday
SolarSystem ss; // Sun=0, Mercury, Venus, ...
EnumExt.TryParse("5", out ss); // true, ss = SolarSystem.Jupiter
残課題
: struct
は、TEnum
を値型に制約しています。できれば enum 型に制約したいのですが、enum 型はクラスではないのでできません。- 作成した
TryParse
は自作クラスのメンバになります。できればEnum
型の拡張メソッドにしたいのですが、静的メソッドでthis
を引数にできないので、拡張メソッドにはできません。
-
C# 7 では、事前の宣言が不要になるようです。 ↩