声明在C#6中使用字符串插值的长字符串
我通常通过连接长字符串来包装它们:声明在C#6中使用字符串插值的长字符串,c#,code-formatting,C#,Code Formatting,我通常通过连接长字符串来包装它们: Log.Debug("I am a long string. So long that I must " + "be on multiple lines to be feasible."); 这是非常有效的,因为编译器处理字符串文本的串联。我也认为这是处理这个问题最干净的方法() 这种方法适用于String.Format: Log.Debug(String.Format("Must resize {0} x {1} image " + "to
Log.Debug("I am a long string. So long that I must " +
"be on multiple lines to be feasible.");
这是非常有效的,因为编译器处理字符串文本的串联。我也认为这是处理这个问题最干净的方法()
这种方法适用于String.Format
:
Log.Debug(String.Format("Must resize {0} x {1} image " +
"to {2} x {3} for reasons.", image.Width, image.Height,
resizedImage.Width, resizedImage.Height));
但是,我现在不希望在这些情况下再次使用String.Format
,因为C#6的字符串插值更具可读性我担心的是,我不再有一种高效而干净的方式来格式化长字符串。
我的问题是,编译器是否能够以某种方式优化以下内容
Log.Debug($"Must resize {image.Width} x {image.Height} image " +
$"to {resizedImage.Width} x {resizedImage.Height} for reasons.");
或者如果有一种替代方法,我可以使用它,它不会降低效率(由于不必要的连接),同时保持代码的干净结构(根据上面链接中提出的要点)。在c#6.0中:
然后与stringbuilder连接:
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(formattedStr);
// Then add the strings you need
将更多字符串附加到stringbuilder…..此程序:
var name = "Bobby Tables";
var age = 8;
String msg = $"I'm {name} and" +
$" I'm {age} years old";
就像您编写的:
var name = "Bobby Tables";
var age = 8;
String msg = String.Concat(String.Format("I'm {0} and", name),
String.Format(" I'm {0} years old", age));
您看到了摆脱Concat
的困难-编译器重新编写了插值文本,以使用String.Format
所需的索引格式设置器,但每个字符串的参数必须从0开始编号。简单地将它们连接起来会导致它们都插入name
。为了正确地解决这个问题,必须在调用$
解析器之间维护状态,以便将第二个字符串重新格式化为“我{1}岁”
。或者,编译器可以尝试应用与字符串文本串联相同的分析。我认为这将是一个合法的优化,尽管字符串插值可能会有副作用,但如果结果是有一个角落的情况下,插值字符串串联改变了程序的行为,我不会感到惊讶。这两种方法听起来都不可能,特别是考虑到逻辑已经存在,可以检测字符串文本的类似情况,但是我可以理解为什么这个特性没有进入第一个版本
我会以您认为最干净、可读性最好的方式编写代码,并且不担心微效率低下,除非它们被证明是一个问题。关于代码主要是供人类理解的这句老话在这里仍然适用。在HTML中使用此字符串的特殊情况下(或使用多个空格不重要的任何解析器进行解析),我建议您使用
@$”
字符串(逐字插入字符串),例如:
也许它不像
+
那样可读,但无论如何,它是可能的。您只需在{
和}
之间划一条线:
Log.Debug($@"Must resize {image.Width} x {image.Height} image to {
resizedImage.Width} x {resizedImage.Height} for reasons.");
SO的着色脚本不能很好地处理这种语法,但C#编译器可以;-) 我看不出它与使用
String.Format
有什么不同的原因。好吧,我在LINQPad中测试过它,当使用C#6的字符串插值时,它肯定会执行一个串联(显式使用String.Format
时不会发生这种情况)。我问的主要是希望有一种替代方法,编译器选项等等。我很惊讶格式字符串没有被视为编译时常量。你可以使用逐字插入字符串来代替($@…
)我认为整个“字符串是不可变的,不要连接它们”的智慧已经失控了。与计算中的任何“规则”一样,这个规则也有很多例外。只有在尝试进行实时(或接近实时)处理时(由于GC的不可预测性,您可能不应该在C#中进行处理),或者如果您正在进行几十次(更现实地说是数百次)的连接时,才会出现问题。将五个字符串串联在一起会在其他所有事情的噪音中丢失。我不会担心这一点,也不会在可读代码方面出错。我不认为这比仅仅使用操作符+
更干净,它将在IL中使用单个Concat
调用(与StringBuilder
一样高效,但可读性更强)。此外,您的代码仍然存在前面提到的问题,即不必要的串联和使用多个String.Format
调用,如果使用单个字符串,则不会出现这种情况。与“+”相比,StringBuilder在使用多个字符串时具有更好的性能。在本例中不一定如此,其中字符串在编译时已知。它被转换为一个String.Concat
调用。使用StringBuilder
的主要原因是避免在重复连接(特别是在循环中连接)时不必要地创建对象。但在这里,我们讨论的是一个典型的相当小的字符串数量,恰好太长,无法干净地换行。另请参见。这似乎只是一个问题,因为编译器没有意识到$“{foo}”+$“{bar}”
与$“{foo}{bar}”
相同。如果它可以先删除连接(在编译时),那么这种优化似乎是有意义的。虽然是的,但目前似乎不可能(需要编译器支持)。我正在使用临时的解决方法,就是不打断我的线路,让VS做软线路包装。这是一个有趣的方法,我没有想到。我喜欢这样,因为我们处于大括号之间,我们可以在不影响字符串的情况下使用空格。我喜欢逐字字符串可以跨行拆分,但必须将其一直向左对齐,这会让我很痛苦,所以我永远不会这样做。
$@"some veeeeeeeeeeery long string {foo}
whatever {bar}"
Log.Debug($@"Must resize {image.Width} x {image.Height} image to {
resizedImage.Width} x {resizedImage.Height} for reasons.");