我有一小段代码解析索引值以确定输入Excel的单元格.这让我想到了......
有什么区别
xlsSheet.Write("C" + rowIndex.ToString(), null, title);
Run Code Online (Sandbox Code Playgroud)
和
xlsSheet.Write(string.Format("C{0}", rowIndex), null, title);
Run Code Online (Sandbox Code Playgroud)
这个比那个好吗?为什么?
Dan*_* C. 154
我最初的偏好(来自C++背景)是针对String.Format的.我稍后放弃了这个原因,原因如下:
- 字符串连接允许空值,String.Format
但不允许.写" s1 + null + s2
"不会中断,它只是将null值视为String.Empty.嗯,这可能取决于您的具体情况 - 有些情况下您需要一个错误而不是默默地忽略null FirstName.然而,即使在这种情况下,我个人更喜欢自己检查空值并抛出特定错误,而不是我从String.Format获得的标准ArgumentNullException.
想法是.NET编译器足够智能转换这段代码:
public static string Test(string s1, int i2, int i3, int i4,
string s5, string s6, float f7, float f8)
{
return s1 + " " + i2 + i3 + i4 + " ddd " + s5 + s6 + f7 + f8;
}
Run Code Online (Sandbox Code Playgroud)
对此:
public static string Test(string s1, int i2, int i3, int i4,
string s5, string s6, float f7, float f8)
{
return string.Concat(new object[] { s1, " ", i2, i3, i4,
" ddd ", s5, s6, f7, f8 });
}
Run Code Online (Sandbox Code Playgroud)
在String.Concat的引擎下发生的事情很容易猜到(使用Reflector).数组中的对象通过ToString()转换为其字符串.然后计算总长度并且仅分配一个字符串(具有总长度).最后,在一些不安全的代码段中,每个字符串都通过wstrcpy复制到结果字符串中.
理由String.Concat
更快?好吧,我们都可以看看String.Format
正在做什么 - 你会惊讶于处理格式字符串所需的代码量.除此之外(我已经看过关于内存消耗的评论),String.Format
在内部使用StringBuilder.这是如何做:
StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
因此,对于每个传递的参数,它保留8个字符.如果参数是一位数的值,那么太糟糕了,我们有一些浪费的空间.如果参数是一个返回一些长文本的自定义对象ToString()
,那么甚至可能需要一些重新分配(当然,最糟糕的情况).
与此相比,连接只会浪费对象数组的空间(不要太多,考虑到它是一个引用数组).格式说明符没有解析,也没有中间StringBuilder.两种方法都存在装箱/拆箱开销.
我选择String.Format的唯一原因是涉及本地化时.将格式字符串放在资源中允许您支持不同的语言而不会弄乱代码(考虑格式化值根据语言改变顺序的情况,即"在{0}小时和{1}分钟之后"在日语中可能看起来完全不同: ).
总结我的第一篇(也很长篇)帖子:
ToString()
调用ToString()
自己打电话以避免拳击(我有点偏向于可读性) - 和你问题中的第一个选项一样String.Format()
则有优势.Jon*_*eet 110
在C#6之前
说实话,我认为第一个版本更简单 - 虽然我将它简化为:
xlsSheet.Write("C" + rowIndex, null, title);
Run Code Online (Sandbox Code Playgroud)
我怀疑其他答案可能会谈到性能损失,但说实话,如果存在,它将是最小的- 并且这个连接版本不需要解析格式字符串.
格式字符串非常适合本地化等目的,但在这样的情况下,连接更简单并且也可以正常工作.
用C#6
字符串插值使C#6中的大部分内容更容易阅读.在这种情况下,您的第二个代码变为:
xlsSheet.Write($"C{rowIndex}", null, title);
Run Code Online (Sandbox Code Playgroud)
这可能是最好的选择,IMO.
我认为第一个选项更具可读性,应该是您最关心的问题.
xlsSheet.Write("C" + rowIndex.ToString(), null, title);
Run Code Online (Sandbox Code Playgroud)
string.Format在引擎盖下使用StringBuilder(使用反射器检查),因此除非您进行大量连接,否则它不会有任何性能优势.对于您的场景来说速度会慢一些,但实际情况是这种微观性能优化决策在大多数情况下是不合适的,除非您处于循环中,否则您应该专注于代码的可读性.
无论哪种方式,首先编写可读性,然后使用性能分析器识别您的热点,如果您真的认为您有性能问题.
对于一个简单的单一连接的简单情况,我觉得它不值得复杂string.Format
(并且我没有测试过,但我怀疑对于像这样的简单情况,string.Format
可能会稍微慢一点,格式字符串解析是什么和所有).和Jon Skeet一样,我更喜欢不显式调用.ToString()
,因为这将由string.Concat(string, object)
重载隐式完成,我认为代码看起来更干净,没有它就更容易阅读.
但是对于多个连接(多少是主观的),我绝对更喜欢string.Format
.在某一点上,我认为可读性和性能都会因连接而受到不必要的影响.
如果格式字符串有很多参数(同样,"很多"是主观的),我通常更喜欢在替换参数上包含注释索引,以免我忘记哪个值转到哪个参数.一个人为的例子:
Console.WriteLine(
"Dear {0} {1},\n\n" +
"Our records indicate that your {2}, \"{3}\", is due for {4} {5} shots.\n" +
"Please call our office at 1-900-382-5633 to make an appointment.\n\n" +
"Thank you,\n" +
"Eastern Veterinary",
/*0*/client.Title,
/*1*/client.LastName,
/*2*/client.Pet.Animal,
/*3*/client.Pet.Name,
/*4*/client.Pet.Gender == Gender.Male ? "his" : "her",
/*5*/client.Pet.Schedule[0]
);
Run Code Online (Sandbox Code Playgroud)
在我看来,我给出的例子有点令人困惑,因为看起来我在这里使用了连接string.Format
.是的,从逻辑上和词汇上来说,这就是我所做的.但是这些连接都将被编译器1优化掉,因为它们都是字符串文字.所以在运行时,会有一个字符串.所以我想我应该说我更喜欢在运行时避免很多连接.
当然,这个主题的大部分内容现在都已过时,除非您仍然使用C#5或更早版本.现在我们已经插入了字符串,为了便于阅读,string.Format
几乎在所有情况下都优于字符串.这些天,除非我只是将值直接连接到字符串文字的开头或结尾,否则我几乎总是使用字符串插值.今天,我会像这样写下我之前的例子:
Console.WriteLine(
$"Dear {client.Title} {client.LastName},\n\n" +
$"Our records indicate that your {client.Pet.Animal}, \"{client.Pet.Name}\", " +
$"is due for {(client.Pet.Gender == Gender.Male ? "his" : "her")} " +
$"{client.Pet.Schedule[0]} shots.\n" +
"Please call our office at 1-900-382-5633 to make an appointment.\n\n" +
"Thank you,\n" +
"Eastern Veterinary"
);
Run Code Online (Sandbox Code Playgroud)
你这样做会失去编译时连接. 每个插值字符串都会转换为string.Format
编译器的调用,并且它们的结果在运行时连接在一起.这意味着这是对可读性的运行时性能的牺牲.大多数时候,这是值得的牺牲,因为运行时间的惩罚可以忽略不计.但是,在性能关键代码中,您可能需要分析不同的解决方案.
1 您可以在C#规范中看到这一点:
...在常量表达式中允许使用以下结构:
...
- 预定义的+ ...二元运算符......
您还可以使用一些代码验证它:
const string s =
"This compiles successfully, " +
"and you can see that it will " +
"all be one string (named `s`) " +
"at run time";
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
84536 次 |
最近记录: |