慎用 Enum.GetHashCode()
公司里遗留下了相当多的 Enum.GetHashCode()来获取枚举值的代码
但是这会产生装箱行为的!!因为Enum是值类型,GetHashCode()是Object的方法,调用GetHashCode必定要装箱成Object类型才能调用
同理:Enum.ToString()也会装箱 用 Enum.GetName( typeof (Color), color);//推荐
namespace EnumBoxTest
{
class Program
{
enum Color
{
None=0,
Red=1,
Black=2
}
static void Main(string[] args)
{
int colorId = Color.Red.GetHashCode();
Console.WriteLine(colorId);
}
}
}
有IL代码有真相
在下面 IL_0002: box EnumBoxTest.Program/Color 代码中,可以清晰看到装箱行为
namespace EnumBoxTest
{
.class private auto ansi beforefieldinit EnumBoxTest.Program
extends [mscorlib]System.Object
{
// 嵌套类型
.class nested private auto ansi sealed Color
extends [mscorlib]System.Enum
{
// 成员
.field public specialname rtspecialname int32 value__
.field public static literal valuetype EnumBoxTest.Program/Color None = int32(0)
.field public static literal valuetype EnumBoxTest.Program/Color Red = int32(1)
.field public static literal valuetype EnumBoxTest.Program/Color Black = int32(2)
} // 类 Color 结束
// 方法
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// 方法起始 RVA 地址 0x2050
// 方法起始地址(相对于文件绝对值:0x0250)
// 代码长度 21 (0x15)
.maxstack 1
.entrypoint
.locals init (
[0] int32 colorId
)
// 文档:\EnumBoxTest\Program.cs, 行 14,列 9
// 0x025C: 00
IL_0000: nop
// 文档:\EnumBoxTest\Program.cs, 行 15,列 13
// 0x025D: 17
IL_0001: ldc.i4.1
// 0x025E: 8C 03 00 00 02
IL_0002: box EnumBoxTest.Program/Color
// 0x0263: 6F 11 00 00 0A
IL_0007: callvirt instance int32 [mscorlib]System.Object::GetHashCode()
// 0x0268: 0A
IL_000c: stloc.0
// 文档: \EnumBoxTest\EnumBoxTest\Program.cs, 行 16,列 13
// 0x0269: 06
IL_000d: ldloc.0
// 0x026A: 28 12 00 00 0A
IL_000e: call void [mscorlib]System.Console::WriteLine(int32)
// 0x026F: 00
IL_0013: nop
// 文档:\EnumBoxTest\EnumBoxTest\Program.cs, 行 18,列 9
// 0x0270: 2A
IL_0014: ret
} // 方法 Program::Main 结束
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// 方法起始 RVA 地址 0x2071
// 方法起始地址(相对于文件绝对值:0x0271)
// 代码长度 7 (0x7)
.maxstack 8
// 0x0272: 02
IL_0000: ldarg.0
// 0x0273: 28 13 00 00 0A
IL_0001: call instance void [mscorlib]System.Object::.ctor()
// 0x0278: 2A
IL_0006: ret
} // 方法 Program::.ctor 结束
} // 类 EnumBoxTest.Program 结束
}
现在将代码换为
namespace EnumBoxTest
{
class Program
{
enum Color
{
None=0,
Red=1,
Black=2
}
static void Main(string[] args)
{
int colorId = (int)Color.Red;
Console.WriteLine(colorId);
}
}
}
IL代码为:
.namespace EnumBoxTest
{
.class private auto ansi beforefieldinit EnumBoxTest.Program
extends [mscorlib]System.Object
{
// 嵌套类型
.class nested private auto ansi sealed Color
extends [mscorlib]System.Enum
{
// 成员
.field public specialname rtspecialname int32 value__
.field public static literal valuetype EnumBoxTest.Program/Color None = int32(0)
.field public static literal valuetype EnumBoxTest.Program/Color Red = int32(1)
.field public static literal valuetype EnumBoxTest.Program/Color Black = int32(2)
} // 类 Color 结束
// 方法
.method private hidebysig static
void Main (
string[] args
) cil managed
{
// 方法起始 RVA 地址 0x2050
// 方法起始地址(相对于文件绝对值:0x0250)
// 代码长度 11 (0xb)
.maxstack 1
.entrypoint
.locals init (
[0] int32 colorId
)
// 文档: \EnumBoxTest\EnumBoxTest\Program.cs, 行 14,列 9
// 0x025C: 00
IL_0000: nop
// 文档:\EnumBoxTest\EnumBoxTest\Program.cs, 行 15,列 13
// 0x025D: 17
IL_0001: ldc.i4.1
// 0x025E: 0A
IL_0002: stloc.0
// 文档: \EnumBoxTest\EnumBoxTest\Program.cs, 行 16,列 13
// 0x025F: 06
IL_0003: ldloc.0
// 0x0260: 28 11 00 00 0A
IL_0004: call void [mscorlib]System.Console::WriteLine(int32)
// 0x0265: 00
IL_0009: nop
// 文档: \EnumBoxTest\EnumBoxTest\Program.cs, 行 18,列 9
// 0x0266: 2A
IL_000a: ret
} // 方法 Program::Main 结束
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// 方法起始 RVA 地址 0x2067
// 方法起始地址(相对于文件绝对值:0x0267)
// 代码长度 7 (0x7)
.maxstack 8
// 0x0268: 02
IL_0000: ldarg.0
// 0x0269: 28 12 00 00 0A
IL_0001: call instance void [mscorlib]System.Object::.ctor()
// 0x026E: 2A
IL_0006: ret
} // 方法 Program::.ctor 结束
} // 类 EnumBoxTest.Program 结束
}
性能测试如下:
enum MyEnum { Blank=0, Write=1 }
class Program { static void Main(string[] args)
{
int v = 0;
Stopwatch sw=new Stopwatch();
sw.Reset();
sw.Start();
for (int i = 0; i < 1000*1000;i++)
{
v = MyEnum.Blank.GetHashCode();
}
sw.Stop();
Console.WriteLine("GetHashCode:{0}",sw.ElapsedMilliseconds);//耗时 81ms
sw.Reset();
sw.Start();
for (int i = 0; i < 1000 * 1000; i++)
{
v = (int)MyEnum.Blank ;
}
sw.Stop();
Console.WriteLine("(int):{0}", sw.ElapsedMilliseconds);//耗时 2ms
Console.Read();
}
}