转换'编译时'类型的最快方法是什么?

Aid*_*api 3 c# performance casting unsafe

我知道标题有点模糊.但我想要实现的是这样的:

在抽象类中:

public abstract bool TryGet<T>(string input, out T output) where T : struct;
Run Code Online (Sandbox Code Playgroud)

在具有此签名的类中:

private class Param<T> : AbstractParam where T : struct
Run Code Online (Sandbox Code Playgroud)

这个实现:

public override bool TryGetVal<TOriginal>(string input, out TOriginal output)
{
    T oTemp;
    bool res = _func(input, out oTemp); // _func is the actual function
                                        // that retrieves the value.
    output = (TOriginal)oTemp; // Compile-time error
    return res;
}
Run Code Online (Sandbox Code Playgroud)

而且TOriginal将永远是相同的类型T.这会绕过编译时错误,但我不想这样做会导致性能下降:

output = (TOriginal)(object)oTemp;
Run Code Online (Sandbox Code Playgroud)

如果它是引用类型,这将提供解决方案:

output = oTemp as TOriginal;
Run Code Online (Sandbox Code Playgroud)

反射/动态也可以解决问题,但性能影响更大:

output = (TOriginal)(dynamic)oTemp;
Run Code Online (Sandbox Code Playgroud)

我尝试使用不安全的代码,但没有成功,但那可能只是我.

所以,我的最大希望是,编译器优化要么(TOriginal)(object)oTemp(TOriginal)oTemp,我不知道.或者说这是一个不安全的方法.

拯救我关于过早优化的讲座,我想知道这纯粹是为了研究,并且有兴趣是否有办法克服这个限制.我意识到这对实际表现的影响可以忽略不计.

最终结论:
在拆解情况后,结果如下:

                return (TOut)(object)_value;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[003314CCh],0 
0000000e  je          00000015 
00000010  call        61A33AD3 
00000015  mov         eax,dword ptr [ebp-4] 
00000018  mov         eax,dword ptr [eax+4] 
0000001b  mov         esp,ebp 
0000001d  pop         ebp 
0000001e  ret 

                return _value;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[004814B4h],0 
0000000e  je          00000015 
00000010  call        61993AA3 
00000015  mov         eax,dword ptr [ebp-4] 
00000018  mov         eax,dword ptr [eax+4] 
0000001b  mov         esp,ebp 
0000001d  pop         ebp 
0000001e  ret 
Run Code Online (Sandbox Code Playgroud)

事实证明,今天的编译器对此进行了优化,因此没有性能成本.

output = (TOriginal)(object)oTemp;
Run Code Online (Sandbox Code Playgroud)

这是最优化的方式:).

谢谢Eric LippertBen Voigt.

关于引用类型的注释:
删除struct约束并传递引用类型(在我的情况下为a string)时,不会进行此优化.

结果:

                return (TOut)(object)_value;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  sub         esp,10h 
00000006  mov         dword ptr [ebp-4],edx 
00000009  mov         dword ptr [ebp-10h],ecx 
0000000c  mov         dword ptr [ebp-8],edx 
0000000f  cmp         dword ptr ds:[003314B4h],0 
00000016  je          0000001D 
00000018  call        61A63A43 
0000001d  mov         eax,dword ptr [ebp-8] 
00000020  mov         eax,dword ptr [eax+0Ch] 
00000023  mov         eax,dword ptr [eax] 
00000025  mov         dword ptr [ebp-0Ch],eax 
00000028  test        dword ptr [ebp-0Ch],1 
0000002f  jne         00000036 
00000031  mov         ecx,dword ptr [ebp-0Ch] 
00000034  jmp         0000003C 
00000036  mov         eax,dword ptr [ebp-0Ch] 
00000039  mov         ecx,dword ptr [eax-1] 
0000003c  mov         eax,dword ptr [ebp-10h] 
0000003f  mov         edx,dword ptr [eax+4] 
00000042  call        617D79D8 
00000047  mov         esp,ebp 
00000049  pop         ebp 
0000004a  ret 

                return _value;
00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[003314B4h],0 
0000000e  je          00000015 
00000010  call        61A639E3 
00000015  mov         eax,dword ptr [ebp-4] 
00000018  mov         eax,dword ptr [eax+4] 
0000001b  mov         esp,ebp 
0000001d  pop         ebp 
0000001e  ret 
Run Code Online (Sandbox Code Playgroud)

如果你想要一种廉价的方式来投射'没有正确的类型检查',那么as运营商就是你的解决方案.

Ben*_*igt 6

我打算给你那个你不想要的讲座,因为你显然不明白.

"测量,测量,测量!"有两个原因!(或等效地"Profile,Profile,Profile!")优化方法:

  1. 把努力放在最有影响力的地方.这就是术语"过早优化"的用武之地.

    有时这个原因不适用(当你想知道理论/出于学术原因).

  2. 找出哪个实现更快.

现代CPU是复杂的野兽,甚至比较两个不同的机器代码序列也无法显示哪个更好,这是由于缓存行为的复杂性,管道数据依赖性,微代码等等.而且你运行的两个级别更高比那(C#代码 - > MSIL - >机器代码).如果不进行测量,将无法确定优化程度.

你说:

这会绕过编译时错误,但我不想这样做会导致性能下降:

output = (TOriginal)(object)oTemp;
Run Code Online (Sandbox Code Playgroud)

但我认为那里确实没有任何表现.对于每种值类型,通用方法都是JITted,该过程应该完全消除任何想象的性能损失.但是,欢迎您通过性能数据(实际分析器测量)或至少反汇编JIT生成的机器代码来证明实际存在成本.


在这种特殊情况下,如果它们始终与您声明的类型相同,则不清楚为什么要开始使用两个不同的泛型类型参数.只是摆脱TOriginal并使用T输出参数的类型.