enumの変換にEnum.ToObjectを使わない

最終更新日


「enum int 変換」などで検索すると、intからenumに変換するにはEnum.ToObjectを使うと説明している記事が出てきます。しかしEnum.ToObjectを使うのは極めて無駄です。単純にintの前に(型名)を付けてキャストできます。これはC#のリファンレンスでも使われています。

計測してみる

Enum.ToObjectを使うと実行時のパフォーマンスも非常に悪いです。BenchmarkDotNetを使った以下のコードで計測してみます。

using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;

[ShortRunJob(RuntimeMoniker.CoreRt60)]
[MemoryDiagnoser]
[MaxColumn, MinColumn, MeanColumn, MedianColumn]
public class CastToEnum
{
    public enum E
    {
        A,
        B,
        C,
    }

    [Benchmark]
    public E CastDirectly()
    {
        return InternalCastDirectly(0);
    }

    private E InternalCastDirectly(int i)
    {
        return (E)i;
    }

    [Benchmark]
    public E CastEnumToObject()
    {
        return InternalCastEnumToObject(0);
    }

    private E InternalCastEnumToObject(int i)
    {
        return (E)Enum.ToObject(typeof(E), i);
    }
}

結果は以下の通りです。直接キャストしたCastDirectlyは速すぎてほとんど計測不能ですがEnum.ToObjectを使ったCastEnumToObjectは60nsもかかっています。

しかも24バイトのメモリアロケーションまで発生しています。これはEnum.ToObjectがobject型で返すためにボックス化が発生しているからです。

InternalCastDirectlyをコンパイルしたILは以下となっています。引数のiを読み込んで返しているだけです。enumとintのバイト列は全く同じなので何もする必要がありません。

IL_0000: ldarg.1
IL_0001: ret

他の整数型からenumに変換も問題なくできます。InternalCastDirectlyの引数をintからlongに変えるとILは以下になります。

IL_0000: ldarg.1
IL_0001: conv.i4
IL_0002: ret

コンパイラが適切に認識してconv.i4でint型にキャストされるようになっています。

まとめ

以上のようにenum型はただの数値型と同じようにキャストできます。Enum.ToObjectが必要になる場面はほとんど存在しません。必ずキャストを使ってください。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

コメントする