通常、最初に値型をボックス化解除し、次に何らかの値型変換を別の値型に実行するには、 2 つのキャストが必要であると予想し、期待します。これが当てはまる例を次に示します。
// create boxed int
IFormattable box = 42; // box.GetType() == typeof(int)
// unbox and narrow
short x1 = (short)box; // fails runtime :-)
short x2 = (short)(int)box; // OK
// unbox and make unsigned
uint y1 = (uint)box; // fails runtime :-)
uint y2 = (uint)(int)box; // OK
// unbox and widen
long z1 = (long)box; // fails runtime :-)
long z2 = (long)(int)box; // OK (cast to long could be made implicit)
私のスマイリーからわかるように、キャストを 1 つだけ使用すると、これらの変換が失敗することを嬉しく思います。結局のところ、1 つの操作で値の型を別の値の型にボックス化解除しようとするのは、おそらくコーディングの誤りです。
IFormattable
(インターフェイスには特別なものはありません。必要に応じてobject
クラスを使用することもできます。)
しかし、今日、これが列挙型では異なることに気付きました (列挙型が同じ基になる型を持つ場合 (およびその場合のみ))。次に例を示します。
// create boxed DayOfWeek
IFormattable box = DayOfWeek.Monday; // box.GetType() == typeof(DayOfWeek)
// unbox and convert to other
// enum type in one cast
DateTimeKind dtk = (DateTimeKind)box; // succeeds runtime :-(
Console.WriteLine(box); // writes Monday
Console.WriteLine(dtk); // writes Utc
この行為は残念だと思います。と言うのは本当に強制されるべき(DateTimeKind)(DayOfWeek)box
です。C# の仕様を読んでも、数値変換と列挙型変換の間のこの違いを正当化する理由はわかりません。この状況では型安全性が失われているように感じます。
これは、将来の .NET バージョンで (仕様の変更なしに) 改善される可能性がある "不特定の動作" だと思いますか? それは重大な変更になります。
DayOfWeek
また、いずれかの列挙型 (またはDateTimeKind
私の例では)のサプライヤが、列挙型のいずれかの基になる型を別のもの ( 、 、 ... のint
可能性があります) に変更することを決定した場合、突然上記のワンキャスト コードは機能しなくなりますが、これはばかげているようです。long
short
もちろん、enumDayOfWeek
とDateTimeKind
は特別なものではありません。これらは、ユーザー定義のものを含む、任意の列挙型である可能性があります。
やや関連:列挙型のボックス化を解除すると奇妙な結果が生じるのはなぜですか? (int
を列挙型に直接アンボックスします)
添加:
OK、非常に多くの回答とコメントが、列挙型が「内部で」どのように扱われるかに焦点を当てています。これはそれ自体興味深いことですが、観察された動作が C# 仕様でカバーされているかどうかにもっと集中したいと思います。
タイプを書いたとします:
struct YellowInteger
{
public readonly int Value;
public YellowInteger(int value)
{
Value = value;
}
// Clearly a yellow integer is completely different
// from an integer without any particular color,
// so it is important that this conversion is
// explicit
public static explicit operator int(YellowInteger yi)
{
return yi.Value;
}
}
そして言った:
object box = new YellowInteger(1);
int x = (int)box;
それでは、これが実行時に成功するかどうかについて、C# の仕様は何かを述べていますか? 私が気にかけているのは、.NET が aを異なる型のメタデータ (またはそれが呼ばれるもの) を持つYellowInteger
単なる an として扱う可能性があることです。では、C# 仕様のどこで成功するか (明示的な演算子メソッドを呼び出す) を確認できますか?Int32
YellowInteger
Int32
(int)box