Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.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# `(Enum)(object)e`和`e as Enum`之间的性能,其中e是结构_C#_.net - Fatal编程技术网

C# `(Enum)(object)e`和`e as Enum`之间的性能,其中e是结构

C# `(Enum)(object)e`和`e as Enum`之间的性能,其中e是结构,c#,.net,C#,.net,我只是想看看什么更快: (枚举)(对象)e e作为枚举 e是一种枚举值类型,通过泛型类型参数指定 我开始用以下代码分析这些: using System; using System.Diagnostics; public class Program { public static void Main() { var list = new DateTimeKind[] { DateTimeKind.Local, DateTimeKind.Unspecifie

我只是想看看什么更快:

  • (枚举)(对象)e

  • e作为枚举

e
是一种枚举值类型,通过泛型类型参数指定

我开始用以下代码分析这些:

using System;
using System.Diagnostics;

public class Program
{
    public static void Main()
    {
        var list = new DateTimeKind[] { DateTimeKind.Local, DateTimeKind.Unspecified, DateTimeKind.Utc };
        var sw = new Stopwatch();

        while (true)
        {
            sw.Restart();
            for (var i = 1; i < 10000000; i++)
                ToSeparatedCommaStringAs<DateTimeKind>(list);
            sw.Stop();
            Console.WriteLine("AS    " + sw.ElapsedTicks);

            sw.Restart();
            for (var i = 1; i < 10000000; i++)
                ToSeparatedCommaStringCast<DateTimeKind>(list);
            sw.Stop();
            Console.WriteLine("CAST  " + sw.ElapsedTicks);

            Console.ReadKey();
        }
    }

    public static string ToSeparatedCommaStringAs<T>(T[] enums)
        where T : struct, IComparable, IFormattable, IConvertible
    {
        var commaString = string.Empty;
        if (!typeof(T).IsEnum)
            throw new ArgumentException("Tipo de enums é inválido");

        foreach (var item in enums)
        {
            Enum enumerador = item as Enum;
            commaString += enumerador.GetStringValue() + ",";
        }

        return commaString.TrimEnd(',');
    }

    public static string ToSeparatedCommaStringCast<T>(T[] enums)
        where T : struct, IComparable, IFormattable, IConvertible
    {
        var commaString = string.Empty;
        if (!typeof(T).IsEnum)
            throw new ArgumentException("Tipo de enums é inválido");

        foreach (var item in enums)
        {
            var enumerador = (Enum)(object)item;
            commaString += enumerador.GetStringValue() + ",";
        }

        return commaString.TrimEnd(',');
    }
}

public static class EnumExt
{
    public static string GetStringValue(this Enum value)
    {
        return "nome"; //só para testar
    }
}
为什么结果如此不同。。。cast版本执行一个box操作,速度应该较慢。。。不是吗

编辑:

我现在已经在发布模式下编译并在没有调试器的情况下运行它,并提高了进程优先级。 时代是这样的:

AS    21305328
CAST  20655717
AS    20330474
CAST  20714744
AS    23156667
CAST  21187540
AS    19841935
CAST  20838702
AS    20180793
CAST  20498759
AS    20782600
CAST  20454898
AS    19819178
CAST  20294181
AS    20244950
CAST  20241214
AS    20919664
CAST  20771469
AS    19990283
CAST  21707570
AS    19759742
CAST  20667567
AS    20259063
CAST  21602690
AS    20200280
CAST  20668826
AS    20147201
CAST  20048725
AS    19845383
CAST  20226356
AS    20169406
CAST  20401720
AS    20826775
CAST  20114984
AS    20691103
CAST  21552342
AS    20200982
CAST  20858057
AS    19734088
CAST  20266943
AS    19589351
CAST  20477856
AS    19813852
CAST  20350659
AS    20180603
CAST  20307336
问题继续

我发现
Enum
是一个引用类型。。。是否有人可以确认
e as Enum
将框装
e
的值,与
(Enum)(object)e
的方式相同。由于
Enum
是引用类型,因此它应该。。。只有在运行时将
Enum
视为特殊对象的情况下(就像
Nullable
一样),才会出现错误

我以前的想法是:

  • e as Enum
    不会将任何内容装箱,并且应该更快
  • (Enum)(object)e
    正在执行长方体操作,速度应该较慢
我怀疑这是真的:

  • e as Enum
    将执行一个box操作
  • (Enum)(object)e
    将执行一个box操作
  • 由于两者都将框定值,因此两者的性能应具有可比性

正如评论中所说,性能度量和计时非常接近,很难说其中一个铸件比另一个快。通过查看生成的IL代码,可以解释为什么性能相互之间是合理的

使用
(Enum)(object)e
强制转换时,会将其装箱。之后,它使用
castclass
操作码。这会将对象推送到堆栈上,然后将其从堆栈中弹出,并将其强制转换为
Enum
类或任何其他类(如果需要)。新创建的对象被推送到堆栈上

当使用
e作为Enum
强制转换时,它也会被装箱。之后,它使用
isinst
操作码。
isinst
castclass
之间的区别在于
isinst
检查堆栈中的推送对象引用是否可以传递到类中。如果无法传递,则返回null。当它成功时,它的行为就像一个
castclass

IL代码isinst

IL_0039: stloc.1
IL_003a: nop
IL_003b: ldloc.1
IL_003c: box !!T
IL_0041: isinst [mscorlib]System.Enum
IL_0046: stloc.2
IL_0047: ldloc.0
IL_0048: ldloc.2
IL代码castclass

IL_0039: stloc.1
IL_003a: nop
IL_003b: ldloc.1
IL_003c: box !!T
IL_0041: castclass [mscorlib]System.Enum
IL_0046: stloc.2
IL_0047: ldloc.0
IL_0048: ldloc.2
希望这对你的问题有所帮助

参考:

对微优化进行基准测试非常困难。当你在处理这个小的计时问题时,各种各样的事情都会发生,而在执行合理的基准测试时,这些事情不会发生。简言之,系统的“噪音”以及基准测试代码本身的成本是不可忽略的,因为在对实际工作中的事情进行基准测试时也是如此。除非你们俩都知道自己在做什么,而且都在做特别敏感的程序,不要把时间浪费在微优化上,你甚至会很难衡量这些微优化的效果。你打印的时间非常清楚地表明,系统的背景噪声远远大于这两个操作之间的任何差异。就性能而言,您应该将它们视为功能相同的。创建对象的新实例(即装箱)是一个非常快速的操作。您只需要将堆指针向上移动一个固定的量,并为这些位分配一些值。在您的应用程序中,没有什么事情比这更快。而且,即使只有一个GC(像这样的对象几乎肯定永远不会),对象也不会存活下来,它不会为GC增加额外的工作。而且,差异很小,很小。问题在于,您的问题是关于性能差异的,您已经证明这些差异可以忽略不计,也不重要。奇怪的是,如果你将其重新表述为询问代码编译和IL生成的机制和差异,那么这样做可能更容易接受:)你的基准测试衡量了99%的其他东西!拳击只是其中的一小部分。这就是为什么差异很小。两个版本的99%相同。混合中甚至还有一些泛型,您也必须删除它们。他们有影响力。
IL_0039: stloc.1
IL_003a: nop
IL_003b: ldloc.1
IL_003c: box !!T
IL_0041: castclass [mscorlib]System.Enum
IL_0046: stloc.2
IL_0047: ldloc.0
IL_0048: ldloc.2