-4

考虑以下代码。's' 被分成两次到两个不同的数组。

string s = "1,2,3";
string[] arr = s.Split(',');
string[] arr2 = s.Split(',');

foreach (..)
{ // do something
}

在发布模式下编译时,IL 看起来像这样,因此 Split 实际上被调用了两次。有没有优化的原因?

IL_0008: newarr [mscorlib]System.Char
IL_000d: stloc.s CS$0$0000
IL_000f: ldloc.s CS$0$0000
IL_0011: ldc.i4.0
IL_0012: ldc.i4.s 44
IL_0014: stelem.i2
IL_0015: ldloc.s CS$0$0000
IL_0017: callvirt instance string[] [mscorlib]System.String::Split(char[])
IL_001c: stloc.1
IL_001d: ldloc.0
IL_001e: ldc.i4.1
IL_001f: newarr [mscorlib]System.Char
IL_0024: stloc.s CS$0$0001
IL_0026: ldloc.s CS$0$0001
IL_0028: ldc.i4.0
IL_0029: ldc.i4.s 44
IL_002b: stelem.i2
IL_002c: ldloc.s CS$0$0001
IL_002e: callvirt instance string[] [mscorlib]System.String::Split(char[])
4

1 回答 1

2

将评论提炼成答案:

一般来说,编译器对方法的内容没有特殊的了解——即使它可以分析当前的实现,它也无法知道该实现是否会在重要细节上发生变化。

您假设编译器可以执行的优化的两个最明显的问题是确定性和副作用的存在。

  1. 确定性 - 即使没有任何(明显的)共享状态,也不能保证对同一函数的两次连续调用会产生相同的结果。

  2. 副作用 - 有问题的函数(或它调用的函数)可能会产生可见的副作用 - 甚至只是增加调用计数器 - 这样调用它一次或两次会产生不同的整体效果。

现在,确实有时,编译器可以完成我们自己无法实现的技巧 - 例如,它可以知道两次连续调用Split(),使用无法分配 a 副本的本地引用更明显的参考,应该产生相同的结果。但这是一个非常具体的优化,可能不值得工程努力。

一般来说,编译器知识并不比方法签名多。而且,在当前的 .NET 版本中,方法签名没有提供有关确定性和副作用的信息。

于 2013-04-15T17:20:52.410 回答