关于c#:拆分长插值字符串

Split long interpolated string

一个例子:

1
2
3
4
5
6
var a = $"Some value 1: {b1:0.00}
Some value 2: {b2}
Some value 3: {b3:0.00000}
Some value 4: {b4:0.00}
Some value 5: {b6:0.0}
Some value 7: {b7:0.000000000}"
;

这有点难读。

我能做到

1
2
3
4
5
6
7
8
9
10
11
var a = $"Some value 1: {b1:0.00}
"
+
        $"Some value 2: {b2}
"
+
        $"Some value 3: {b3:0.00000}
"
+
        $"Some value 4: {b4:0.00}
"
+
        $"Some value 5: {b6:0.0}
"
+
        $"Some value 7: {b7:0.000000000}";

但这里有一条评论说,这将是对string.Format的多个调用,我认为它会(不知道如何检查,IL对我来说是一个黑盒子)。

问题:可以吗?拆分长内插字符串还有哪些其他选项?


what this will be multiple calls to string.Format and I think it will

你说得对。你没有说你为什么在乎。为什么要避免?

is it ok to do?

我没事。

What are other options to split long interpolated string?

我将使用逐字插入字符串。那会很好地解决你的问题。

如何使用带插值的逐字字符串?

(因为这是你在问题中提到的链接,所以我不完全清楚你为什么问这个问题,因为你已经阅读了一个建议好答案的页面。)

I don't like $@ idea, it makes it worse than long string

你可能早点说过。

can't it be accidentally damaged by reformatting sources?

所有代码都可以通过更改源代码来更改。

What are other options to split long interpolated string?

一开始不要插补。使字符串成为资源,使类负责获取格式化的资源字符串,并隐藏如何在类的方法中格式化字符串的实现细节。


编译器做什么?好的。

从这里开始:好的。

1
2
3
4
5
6
7
8
9
10
11
var a = $"Some value 1: {b1:0.00}
"
+
        $"Some value 2: {b2}
"
+
        $"Some value 3: {b3:0.00000}
"
+
        $"Some value 4: {b4:0.00}
"
+
        $"Some value 5: {b6:0.0}
"
+
        $"Some value 7: {b7:0.000000000}";

IL is a black box for me yet

Ok.

为什么不直接打开它呢?使用像ilspy、reflector等工具很容易。好的。

在代码中会发生的事情是,每一行都被编译成一个string.Format。规则很简单:如果您有$"...{X}...{Y}...",它将被编译为string.Format("...{0}...{1}...", X, Y)。另外,+运算符将引入字符串串联。好的。

更详细地说,string.Format是一个简单的静态调用,这意味着编译器将使用call操作码而不是callvirt操作码。好的。

从所有这些可以推断,编译器很容易对其进行优化:如果我们有一个像constant string + constant string + ...这样的表达式,您可以简单地用constant string替换它。您可以认为编译器对string.Format的内部工作和字符串连接有一定的了解,并能处理这些问题。另一方面,你可以争辩说它不应该。让我详细说明两个注意事项:好的。

注意,字符串是.NET中的对象,但它们是"特殊的"。你可以从有一个特殊的ldstr操作码的事实中看到这一点,但是如果你在字符串上检查switch会发生什么,编译器会生成一个字典。因此,您可以由此推断出编译器"知道"string如何在内部工作。我们来看看它是否知道如何进行连接,好吗?好的。

1
2
var str ="foo" +"bar";
Console.WriteLine(str);

在IL(当然是释放模式)中,这将给出:好的。

1
L_0000: ldstr"foobar"

tl;dr:所以,不管插入字符串的连接是否已经实现(它们没有实现),我都非常有信心编译器最终会处理这种情况。好的。

JIT是做什么的?好的。

下一个问题是:使用字符串的JIT编译器有多聪明?好的。

那么,让我们考虑一下,我们将教编译器有关string的所有内部工作。首先,我们应该注意到C_被编译到IL,而IL是JIT编译到汇编程序的。在switch的情况下,JIT编译器很难创建字典,因此我们必须在编译器中创建字典。另一方面,如果我们处理的是更复杂的连接,那么使用我们已经为f.ex.integer算术提供的东西来执行字符串操作也是有意义的。这意味着将字符串操作放入JIT编译器中。让我们用一个例子来考虑一下:好的。

1
2
3
4
5
var str ="";
for (int i=0; i<10; ++i) {
    str +="foo";
}
Console.WriteLine(str);

编译器将简单地编译到IL的串联,这意味着IL将拥有一个非常直接的实现。在这种情况下,展开循环可以为程序的(运行时)性能带来很多好处:它可以简单地展开循环,将字符串追加10次,从而得到一个简单的常量。好的。

但是,将这些知识提供给JIT编译器会使其更加复杂,这意味着运行时将在JIT编译(计算出优化)上花费更多时间,执行(运行发出的汇编程序)的时间更少。剩下的问题是:会发生什么?好的。

启动程序,在写行上放置一个断点,然后点击ctrl-alt-d并查看汇编程序。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
00007FFCC8044413  jmp         00007FFCC804443F  
            {
                str +="foo";
00007FFCC8044415  mov         rdx,2BEE2093610h  
00007FFCC804441F  mov         rdx,qword ptr [rdx]  
00007FFCC8044422  mov         rcx,qword ptr [rbp-18h]  
00007FFCC8044426  call        00007FFD26434CC0  

[...]
00007FFCC804443A  inc         eax  
00007FFCC804443C  mov         dword ptr [rbp-0Ch],eax  
00007FFCC804443F  mov         ecx,dword ptr [rbp-0Ch]  
00007FFCC8044442  cmp         ecx,0Ah  
00007FFCC8044445  jl          00007FFCC8044415

tl;dr:不,这没有优化。好的。

但我也希望JIT优化这一点!好的。

是的,嗯,我不太确定我是否同意这个观点。在运行时性能和JIT编译所花费的时间之间有一个平衡。注意,如果你这样做的话,我会认为你是在自找麻烦。另一方面,如果这是一个常见且微不足道的情况(比如连接的常量),那么优化就非常容易,并且不会影响运行时。好的。

换句话说:可以说,您不希望JIT对此进行优化,前提是这将花费太多时间。我相信我们可以信任微软明智地做出这个决定。好的。

另外,您应该认识到.NET中的字符串是高度优化的。我们都知道他们被大量使用,微软也是如此。如果你不是在写"非常愚蠢的代码",那么这是一个非常合理的假设,即它的性能会很好(除非得到证明)。好的。

选择?好的。

What are other options to split long interpolated string?

Ok.

使用资源。资源是处理多种语言的有用工具。如果这只是一个小的,非专业的项目,我根本就不会麻烦。好的。

或者,可以使用常量字符串连接的事实:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
var fmt ="Some value 1: {1:0.00}
"
+
         "Some value 2: {2}
"
+
         "Some value 3: {3:0.00000}
"
+
         "Some value 4: {4:0.00}
"
+
         "Some value 5: {6:0.0}
"
+
         "Some value 7: {7:0.000000000}";

var a = string.Format(fmt, b1, b2, b3, b4, b5, b6, b7);

好啊。