c# - 转换 'compile-time' 类型最快的方法是什么?

标签 c# performance casting unsafe

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

在抽象类中:

public abstract bool TryGet<T>(string input, out T output) where T : struct;

在具有此签名的类中:

private class Param<T> : AbstractParam where T : struct

这个实现:

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;
}

并且 TOriginal 将始终与 T 的类型相同。 这会绕过编译时错误,但我没有想要这样做会导致性能下降:

output = (TOriginal)(object)oTemp;

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

output = oTemp as TOriginal;

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

output = (TOriginal)(dynamic)oTemp;

我尝试使用不安全的代码,但没有成功,但这可能就是我。

所以我最大的希望是编译器将 (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 

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

output = (TOriginal)(object)oTemp;

这是最优化的方法:)。

谢谢 Eric LippertBen Voigt .

关于引用类型的注释:
当删除 struct 约束并传递引用类型(在我的例子中是 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 

如果您想要一种廉价的方式转换为“无需适当的类型检查”,as 运算符就是您的解决方案。

最佳答案

我要给你上你不想听的课,因为你显然不明白。

“衡量、衡量、衡量!”有两个原因。 (或等同于“配置文件、配置文件、配置文件!”)优化方法:

  1. 将精力放在影响最大的地方。这就是术语“过早优化”的由来。

    有时这个原因不适用(当您想了解理论/出于学术原因时)。

  2. 找出哪个实现实际上更快。

现代 CPU 是复杂的野兽,由于缓存行为、管道数据依赖性、微代码等的复杂性,即使比较两个不同的机器代码序列也无法显示哪个更好。而且你正在操作比它高两个级别(C# 代码 -> MSIL -> 机器代码)。如果不进行测量,就无法确定会进行哪些优化。

你说:

This'd bypass the compile-time error, but I don't want to do this cause of the performance hit:

output = (TOriginal)(object)oTemp;

但我认为实际上没有任何性能受到影响。通用方法针对每种值类型进行 JIT 处理,该过程应该完全消除任何想象中的性能损失。但欢迎您通过性能数据(实际分析器测量)或至少通过反汇编 JIT 生成的机器代码来证明确实存在成本。


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

关于c# - 转换 'compile-time' 类型最快的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8954578/

相关文章:

c# - 如何从任意字符串生成有效的 Windows 文件名?

C# - SQL - 动态数组字段可能吗?

c# - 重复使用套接字还是每次都创建一个新套接字?

mysql - 如何提高选择案例的性能?

mysql - 处理小数精度

c# - 手动触发作业不起作用

android - 如何获取Android应用程序中某些功能的CPU使用率?

windows - Zend Framework 在 WAMP 上的性能非常糟糕

c# - 我可以创建自定义隐式类型转换吗?

c++ - 来自特征系数明智比较的数字类型