我很想知道什么更快:
(Enum)(object)e
e as Enum
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 版本在我的机器上运行得更快。其他人已经测试了不同的结果。有人说as
运算符总是更快,有些人说它在运行之间会有所不同。
我在运行时分析了disassemlby窗口,代码不同:
Lines with an `x` were in fact executed:
Enum enumerador = item as Enum;
x 001E349D mov ecx,707E5288h
x 001E34A2 call 000C30F4
x 001E34A7 mov dword ptr [ebp-34h],eax
x 001E34AA mov eax,dword ptr [ebp-34h]
x 001E34AD mov edx,dword ptr [ebp-0Ch]
x 001E34B0 mov dword ptr [eax+4],edx
x 001E34B3 mov eax,dword ptr [ebp-34h]
x 001E34B6 mov dword ptr [ebp-58h],eax
x 001E34B9 mov edx,dword ptr [ebp-58h]
x 001E34BC mov ecx,707CF474h
x 001E34C1 call 715D0260
x 001E34C6 mov dword ptr [ebp-24h],eax
var enumerador = (Enum)(object)item;
x 001E39F0 mov ecx,707E5288h
x 001E39F5 call 000C30F4
x 001E39FA mov dword ptr [ebp-34h],eax
x 001E39FD mov eax,dword ptr [ebp-34h]
x 001E3A00 mov edx,dword ptr [ebp-0Ch]
x 001E3A03 mov dword ptr [eax+4],edx
x 001E3A06 mov eax,dword ptr [ebp-34h]
x 001E3A09 mov dword ptr [ebp-38h],eax
x 001E3A0C cmp dword ptr [ebp-38h],0
x 001E3A10 je 001E3A31
x 001E3A12 mov eax,dword ptr [ebp-38h]
x 001E3A15 cmp dword ptr [eax],707CF474h
x 001E3A1B jne 001E3A22
001E3A1D mov eax,dword ptr [ebp-38h]
001E3A20 jmp 001E3A2F
x 001E3A22 mov edx,dword ptr [ebp-38h]
x 001E3A25 mov ecx,707CF474h
x 001E3A2A call 715D2582
x 001E3A2F jmp 001E3A34
001E3A31 mov eax,dword ptr [ebp-38h]
x 001E3A34 mov dword ptr [ebp-24h],eax
为什么结果差异太大......演员版本进行了一个盒子操作,它应该更慢......不是吗?
修改
我现在已经在发布模式下编译并在没有调试器的情况下运行它并提高了进程优先级。 时间是这样的:
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<T>
视为特殊内容(就像e as Enum
一样)
我之前的想法:
(Enum)(object)e
不会包装任何东西,而且应该更快e as Enum
正在进行一个盒子操作,而且应该更慢我怀疑这是真的:
(Enum)(object)e
将执行框操作答案 0 :(得分:2)
正如评论中所说,表现指标和时间彼此如此接近,很难说其中一个铸件比另一个铸件更快。看一下生成的IL代码,可以解释为什么性能对彼此是合理的。
使用(Enum)(object)e
投射时,它会被装箱。之后,它使用castclass
OpCode。这会将一个对象推入堆栈,然后将其从堆栈中弹出并将其转换为Enum
类或任何其他类(如果需要)。新创建的对象被压入堆栈。
使用e as Enum
投射时,它也会装箱。之后,它使用isinst
OpCode。 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
希望这对您有所帮助。
参考:https://msdn.microsoft.com/library/system.reflection.emit.opcodes.isinst.aspx https://msdn.microsoft.com/library/system.reflection.emit.opcodes.castclass.aspx