Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#为对象指定枚举值_C#_Performance_Object_Enums_Box - Fatal编程技术网

C#为对象指定枚举值

C#为对象指定枚举值,c#,performance,object,enums,box,C#,Performance,Object,Enums,Box,在代码的某些地方,我们将枚举值指定给对象变量(例如:object value=DayOfWeek.Sunday)。我在想枚举的底层类型是int,所以为什么不使用(int)然后调用.ToString()来避免装箱呢。令我高兴的是,它似乎避免了装箱(我检查了IL代码),但令我惊讶的是,代码的这一部分花费了更多的时间来执行,并分配了更多的内存。我使用BenchmarkDotNet工具测试性能差异。下面是代码示例 1) 返回枚举值,发生装箱(下面的IL代码) 2) 使用(int),仍然会发生装箱,这是可

在代码的某些地方,我们将枚举值指定给对象变量(例如:object value=DayOfWeek.Sunday)。我在想枚举的底层类型是int,所以为什么不使用(int)然后调用.ToString()来避免装箱呢。令我高兴的是,它似乎避免了装箱(我检查了IL代码),但令我惊讶的是,代码的这一部分花费了更多的时间来执行,并分配了更多的内存。我使用BenchmarkDotNet工具测试性能差异。下面是代码示例

1) 返回枚举值,发生装箱(下面的IL代码)

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()方法

令我惊讶的是,BenchmarkDotNet工具显示,方法3(AssingEnumIntStringToObject)花费的时间更长,分配的内存也更多

我错过了什么?这是因为CSharp语言规范中的“从任何枚举类型到System.enum类型”规则吗?如果是,这是如何工作的

请给我解释一下。谢谢

编辑:


谢谢@JonSkeet和@Craig的回答。我没有考虑创建字符串引用的成本。我现在明白了

方法3花费的时间更长,因为它向ToString添加了一个函数调用,并分配和分配了一个字符串,所有这些都需要额外的时间


方法3占用了更多内存,因为它正在分配字符串。与装箱转换一样,这是添加引用(指针大小),但也添加字符串本身。字符串的大小至少与int相同:至少,它有一个大小计数器(我相信是四个字节)加上字符缓冲区(您的案例中至少有一个字符)。因此,与其他两个最多只添加一个引用(指针大小)的内存相比,这占用了两倍多的额外内存。

您实际想要实现什么?将枚举值分配给
对象
变量与分配字符串值完全不同。如果你想得到一个字符串表示,为什么要强制转换呢?如果不清楚您想要的结果是什么,那么任何人试图帮助您进行优化都是没有意义的——您在这里给出了三个完全不同的结果。Hi@JonSkeet实际上,我正在将枚举值分配给sqlparameter类,其值参数的类型为object。公共SqlParameter(string parameterName,object value)例如:新的SqlParameter(“@Day”,DayOfWeek.Sunday),我想转换为字符串表示将避免不必要的装箱。所以,我只是试着检查一下它的行为和工作原理。如果可能的话,你能解释一下为什么它有三个完全不同的结果吗?我是第一次问你。很抱歉,如果我的提问方式不对。如果您正在创建一个
SqlParameter
,那么您可能要将其发送到SQL。拳击的成本与这一成本相比是毫不相干的。(以及为什么它们是不同的:一个是装箱的枚举值,一个是装箱的int,一个是字符串引用,那些是不同的类型……)“字符串引用”-是的,错过了完全考虑这一点。非常感谢您的快速回复。顺便说一句:我经常读你们的博客(虽然我从未发表过评论,很抱歉,我还在学习阶段)。太棒了。再次感谢您的来信:)嗨,克雷格,谢谢。乔恩·斯基特给了我一个好主意,你给了我一个详细的建议。所以,让int-type成为box比使用ToString()要好得多?比如string.concat()(或“+”运算符)用法。如果要将其放入字符串中,那么无论如何在某个时刻都会发生字符串转换。我建议不要单独分析这个特定的操作。如果这确实是一个重要的瓶颈,那么对整个操作(包括concat或operator+)进行分析;不要只是比较这一部分。盒装版本在其他地方进行字符串转换时会产生开销,而这些性能细节往往很难仅从检查中发现。
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
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