列挙型を使用する場合、以下を使用する方が良いですか?
if (enumInstance.Equals(MyEnum.SomeValue))
または使用する
if (enumInstance == MyEnum.SomeValue)
どちらか一方を使用して重要な考慮事項はありますか?
enumInstance
のコンパイル時型が列挙型の場合、==
で問題ありません。
enumInstance
のコンパイル時タイプがEnum
、ValueType
、またはObject
である場合、Equals
を使用する必要があります。 (その場合、==
を使用しようとすると、コンパイル時エラーが発生します。)
現在、列挙型は.NETの命名規則に違反していることに注意してください。通常はMyEnum.Value
です。
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を実行します
ここでの他の答えは、他の人を助けるかもしれないと言及していない場合があります。
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
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;
}
}