web-dev-qa-db-ja.com

c#enum equals()vs ==

列挙型を使用する場合、以下を使用する方が良いですか?

if (enumInstance.Equals(MyEnum.SomeValue))

または使用する

if (enumInstance == MyEnum.SomeValue)

どちらか一方を使用して重要な考慮事項はありますか?

49
ToddBFisher

enumInstanceのコンパイル時型が列挙型の場合、==で問題ありません。

enumInstanceのコンパイル時タイプがEnumValueType、またはObjectである場合、Equalsを使用する必要があります。 (その場合、==を使用しようとすると、コンパイル時エラーが発生します。)

現在、列挙型は.NETの命名規則に違反していることに注意してください。通常はMyEnum.Valueです。

52
Jon Skeet

Equalsの代わりに==を使用すると少し速くなります。列挙型をボックス化する必要はなく、ここで必要な関数呼び出しはサンプルc#コードとそのために生成されたMSILです。

 class Program
    {
        static void Main(string[] args)
        {
            var instance = MyEnum.First;

            if (instance == MyEnum.First)
            {
                Console.WriteLine("== Called");
            }

            if (instance.Equals(MyEnum.First))
            {
                Console.WriteLine("Equals called");
            }

        }     
    }

    enum MyEnum { First = 99, Second = 100}

MSIL:

IL_0000:  nop
  IL_0001:  ldc.i4.s   99
  IL_0003:  stloc.0
  IL_0004:  ldloc.0
  IL_0005:  ldc.i4.s   99
  IL_0007:  ceq
  IL_0009:  ldc.i4.0
  IL_000a:  ceq
  IL_000c:  stloc.1
  IL_000d:  ldloc.1
  IL_000e:  brtrue.s   IL_001d
  IL_0010:  nop
  IL_0011:  ldstr      "== Called"
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001b:  nop
  IL_001c:  nop
  IL_001d:  ldloc.0
  IL_001e:  box        ConsoleApplication1.MyEnum
  IL_0023:  ldc.i4.s   99
  IL_0025:  box        ConsoleApplication1.MyEnum
  IL_002a:  callvirt   instance bool [mscorlib]System.Object::Equals(object)
  IL_002f:  ldc.i4.0
  IL_0030:  ceq
  IL_0032:  stloc.1
  IL_0033:  ldloc.1
  IL_0034:  brtrue.s   IL_0043
  IL_0036:  nop
  IL_0037:  ldstr      "Equals called"
  IL_003c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0041:  nop
  IL_0042:  nop
  IL_0043:  ret

ご覧のとおり、==はceq命令を生成し、Equalsメソッドはボクシングとcallvirtを実行します

27

ここでの他の答えは、他の人を助けるかもしれないと言及していない場合があります。

C#では、列挙型の基本型は整数です。整数であるため、論理的にOR列挙型を一緒にできます。

上記のメソッドのいずれかを使用して等値化する場合、enumが論理的にORで結合されていると失敗します。

そのため、フラグとして列挙型を使用するなど、いくつかの特殊なケースでは、論理的にANDをテストする場合に、同等性をチェックする前に最初にテストする必要があります。

if ((enumInstance & MyEnum.SomeValue).Equals(MyEnum.SomeValue))

または

if ((enumInstance & MyEnum.SomeValue) == MyEnum.SomeValue)

厳密に言えば、列挙型で「==」を使用するのが最も安全です。

可能な列挙型の完全なリストは、ここにあります: https://docs.Microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum

2
user3416682

Jon Skeetの古い答えの拡張として、Enum == YourActualEnum.Valueを比較するとコンパイルエラーが発生するのは事実ですが、正常にコンパイルされるEnum == Enumを実行すると、常にfalseが返されます。

public class TestClass
{
    public bool TestMethod1()
    {
        bool Result = false;

        Enum l_Value = TEST_ENUM.TEST_VALUE_1;

        Enum l_Check_Value = TEST_ENUM.TEST_VALUE_1;

        Result = l_Value == l_Check_Value;

        return Result;
    }

    public bool TestMethod2()
    {
        bool Result = false;

        TEST_ENUM l_Value = TEST_ENUM.TEST_VALUE_1;

        TEST_ENUM l_Check_Value = TEST_ENUM.TEST_VALUE_1;

        Result = l_Value == l_Check_Value;

        return Result;
    }

    public bool TestMethod3()
    {
        bool Result = false;

        Enum l_Value = TEST_ENUM.TEST_VALUE_1;

        Enum l_Check_Value = TEST_ENUM.TEST_VALUE_1;

        Result = l_Value.Equals(l_Check_Value);

        return Result;
    }

    public enum TEST_ENUM
    {
        TEST_VALUE_1,
        TEST_VALUE_2,
        TEST_VALUE_3
    }
}

テストアプリで以下を試してみると、次のものが得られます

Console.WriteLine("Method 1 result: {0}", myClass.TestMethod1());

Console.WriteLine("Method 2 result: {0}", myClass.TestMethod2());

Console.WriteLine("Method 3 result: {0}", myClass.TestMethod3());

次の結果が得られます

Method 1 result: False Method 2 result: True Method 3 result: True

なぜEnumとEnumを比較するのか疑問に思うなら... WPFプロジェクトのEnumConverterとFlagConvertを作成する際にスマートにしようとして、それを発見しました。そこでは、パラメーターとしてオブジェクト値のみを受け取り、フラグコンバーターに対して、特にフラグが選択されていない場合に特別なテキストを提供したかった(つまり、enumの値は0であり、静的メンバーはありません)。

これ以外は機能しませんでした(value.Equals(0)、value.Equals((int)0)を含む)。

l_Source_Type = value.GetType();

if (l_Source_Type.IsDefined(typeof(FlagsAttribute)))
{
    Enum l_Value = (Enum)value;

    Enum l_Check_Value = (Enum)Enum.ToObject(l_Source_Type, 0);

    if (l_Value.Equals(l_Check_Value))
    {
        return String.Empty;
    }
}
1
user1464603