简体   繁体   English

C#中具有静态类型检查的C#中的索引的Typedef,而没有运行时开销

[英]Typedef for indexes in C# with static type checking without runtime overhead

It's pretty common case to use multidimensional arrays with complicated indexing. 使用具有复杂索引的多维数组是很常见的情况。 It's really confusing and error-prone when all indexes are ints because you can easily mix up columns and rows (or whatever you have) and there's no way for compiler to identify the problem. 当所有索引都是整数时,这真的很容易混淆,并且容易出错,因为您可以轻松地混合列和行(或您所拥有的任何东西),并且编译器无法识别问题。 In fact there should be two types of indexes: rows and columns but it's not expressed on type level. 实际上,应该有两种类型的索引:行和列,但是它不是在类型级别上表示的。

Here's a small illustration of what I want: 这是我想要的一个小例子:

var table = new int[RowsCount,ColumnsCount];
Row row = 5;
Column col = 10;
int value = table[row, col];

public void CalcSum(int[,] table, Column col)
{
    int sum = 0;
    for (Row r = 0; r < table.GetLength(0); r++)
    {
        sum += table[row, col];
    }
    return sum;
}

CalcSum(table, col); // OK
CalcSum(table, row); // Compile time error

Summing up: 加起来:

  • indexes should be statically checked for mixing up (kind of type check) 应该对索引进行静态检查以防混淆(类型检查)
  • important! 重要! they should be run time efficient since it's not OK for performance to wrap ints to custom objects containing the index and then unwrapping them back 它们应该是运行时高效的,因为将int封装到包含索引的自定义对象上然后将它们解开会降低性能
  • they should be implicitly convertible to ints in order to serve as indexes in native multidimensional arrays 它们应隐式转换为int以便在本机多维数组中用作索引

Is there any way to achieve this? 有什么办法可以做到这一点? The perfect solution would be something like typedef which serves as compile-time check only compiling into plane ints. 理想的解决方案是像typedef这样的东西,它仅用作编译时检查以编译为平面int。

You'll only get a 2x slowdown with the x64 jitter. x64抖动只会使速度减慢2倍。 It generates interesting optimized code. 它生成有趣的优化代码。 The loop that uses the struct looks like this: 使用该结构的循环如下所示:

00000040  mov         ecx,1 
00000045  nop         word ptr [rax+rax+00000000h] 
00000050  lea         eax,[rcx-1] 
                s.Idx = j;
00000053  mov         dword ptr [rsp+30h],eax 
00000057  mov         dword ptr [rsp+30h],ecx 
0000005b  add         ecx,2 
            for (int j = 0; j < 100000000; j++) {
0000005e  cmp         ecx,5F5E101h 
00000064  jl          0000000000000050 

This requires some annotation since the code is unusual. 由于代码不常见,因此需要一些注释。 First off, the weird NOP at offset 45 is there to align the instruction at the start of the loop. 首先,偏移量为45的怪异NOP会在循环开始时对齐指令。 That makes the branch at offset 64 faster. 这使得偏移量为64的分支更快。 The instruction at 53 looks completely unnecessary. 53处的指令看起来完全没有必要。 What you see happen here is loop unrolling , note how the instruction at 5b increments the loop counter by 2. The optimizer is however not smart enough to then also see that the store is unnecessary. 您在这里看到的是循环展开 ,请注意5b处的指令如何将循环计数器加2。然而,优化器不够智能,因此也看不到存储区。

And most of all note that there's no ADD instruction to be seen. 最重要的是,这里没有ADD指令。 In other words, the code doesn't actually calculate the value of "sum". 换句话说,该代码实际上并没有计算“ sum”的值。 Which is because you are not using it anywhere after the loop, the optimizer can see that the calculation is useless and removed it entirely. 这是因为在循环后没有在任何地方使用它,优化器可以看到该计算是无用的,并将其完全删除了。

It does a much better job at the second loop: 在第二个循环中,它做得更好:

000000af  xor         eax,eax 
000000b1  add         eax,4 
            for (int j = 0; j < 100000000; j++) {
000000b4  cmp         eax,5F5E100h 
000000b9  jl          00000000000000B1 

It now entirely removed the "sum" calculation and the "i" variable assignment. 现在,它完全删除了“求和”计算和“ i”变量分配。 It could have also removed the entire for() loop but that's never done by the jitter optimizer, it assumes that the delay is intentional. 它也可能删除了整个for()循环,但是抖动优化器从未做到这一点,它假设延迟是有意的。

Hopefully the message is clear by now: avoid making assumptions from artificial benchmarks and only ever profile real code. 希望到目前为止,信息已经清楚了:避免根据人工基准进行假设,并且只能描述真实的代码。 You can make it more real by actually displaying the value of "sum" so the optimizer doesn't throw away the calculation. 您可以通过实际显示“ sum”的值来使其更真实,这样优化器就不会丢弃计算。 Add this line of code after the loops: 在循环之后添加以下代码行:

        Console.Write("Sum = {0} ", sum);

And you'll now see that there's no difference anymore. 现在,您将看到没有任何区别了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM