在我们代码的某些地方,我们将枚举值赋给对象变量(例如:object value = DayOfWeek.Sunday)。我在思考枚举底层类型的行是int,所以为什么不使用(int)然后调用.ToString()来避免装箱。为了我的幸福,它似乎避免拳击(我检查了IL代码),但令我惊讶的是,这部分代码花了更多的时间来执行和分配更多的内存。我使用BenchmarkDotNet工具来测试性能差异。以下是代码示例
1)返回枚举值,发生装箱(下面的IL代码)
public object AssingEnumToObject()
{
return DayOfWeek.Sunday;
}
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: box [mscorlib]System.DayOfWeek
IL_0006: ret
2)使用(int),仍然可以理解拳击。
public object AssingEnumIntToObject()
{
return (int)DayOfWeek.Sunday;
}
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: box [mscorlib]System.Int32
IL_0006: ret
3)使用(int)然后使用ToString()。现在为需要对象返回类型的方法返回它的字符串。在IL中没有装箱但是调用了Int32.ToString()方法。
public object AssingEnumIntStringToObject()
{
return ((int)DayOfWeek.Sunday).ToString();
}
// Code size 10 (0xa)
.maxstack 1
.locals init ([0] int32 V_0)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call instance string [mscorlib]System.Int32::ToString()
IL_0009: ret
令我惊讶的是,BenchmarkDotNet工具显示,方法3(AssingEnumIntStringToObject)需要更长时间并分配更多内存。
Results of BenchmarkDotNet tool 我在这里错过了什么?是否因为CSharp语言规范中的这个规则“从任何枚举类型到类型System.Enum”?如果是这样,这是如何工作的?
请解释一下。谢谢。
编辑:
感谢@JonSkeet和@Craig的答案。我没有考虑创建字符串引用的成本。我现在明白了。
答案 0 :(得分:1)
方法3花费的时间更长,因为它正在向ToString添加函数调用并分配和分配字符串,所有这些都需要额外的时间。
方法3占用更多内存,因为它正在分配字符串。与装箱转换一样,这是添加引用(指针大小),但它也添加了字符串本身。字符串至少是int的大小:至少,它有一个大小的计数器(我相信四个字节)加上字符的缓冲区(对于你的情况最少一个字符)。因此,这需要额外内存的两倍以上,而其他两个内存最多只添加一个引用(指针大小)。