[英]Using StringBuilder for constant strings in C#?
在我當前的項目中,他們將每個SQL查詢都放在“ QueryList”類中,每個查詢都是一個不同的Get方法。 我不明白的是,它們在這些方法中使用StringBuilder來構建常量字符串,沒有在其中使用任何操作或串聯。 當我對此提出疑問時,他們說,最好使用串聯。 據我所知,字符串文字的串聯由編譯器解決,對嗎? 編譯器中是否對此類StringBuilder代碼進行了優化?
我在Java中看到了類似的問題( 用於常量的Stringbuilder ),對於C#是否應該相同?
public static class QueryList
{
private static StringBuilder GetQuery
{
get
{
StringBuilder query = new StringBuilder();
query.Append(" INSERT INTO ");
query.Append(" MyTable ");
query.Append(" (column1, column2) ");
query.Append(" VALUES ");
query.Append(" (@val1 , @val2) ");
return query;
}
}
}
然后在其中被稱為
string query = QueryList.GetQuery.ToString();
我進行了一些計數,大約有700個調用此類方法的方法,所有方法后均帶有“ .ToString();”。 我知道在進行實際的字符串連接時會更好,但是只有34個需要它的調用。 該程序每秒大約有200個查詢。
如果要返回常量 string
,請執行以下操作:
// I've removed "Get" from the name
private const string Query =
@"INSERT INTO MyTable (
column1,
column2)
VALUES (
@val1,
@val2)";
在StringBuilder
不需要
編譯器中是否對此類StringBuilder代碼進行了一些優化
不。它將每次運行。
沒有完美的方法將多行字符串文字嵌入C#(不幸的是)。 在這些選項中,這是我最喜歡的SQL查詢:
private static string SomeQuery
{
get
{
var query = @"
INSERT INTO
MyTable (column1, column2)
values (@val1, @val2)
";
return query;
}
}
這里沒有優化-使用StringBuilder不僅毫無意義,而且會嚴重損害代碼的效率。 有問題的屬性將始終返回以下字符串:
INSERT INTO MyTable (column1, column2) VALUES (@val1 , @val2)
話雖如此,如果您要連接多個字符串文字,那么任何現代C#編譯器都將意識到,它應該在編譯時而不是在運行時執行。 通過示例,請考慮以下代碼:
void Main()
{
string a = "a" + "b" + "c";
string b = "def";
Console.WriteLine(a);
Console.WriteLine(b);
}
使用LINQpad 5,它將編譯為以下IL:
IL_0000: nop
IL_0001: ldstr "abc"
IL_0006: stloc.0 // a
IL_0007: ldstr "def"
IL_000C: stloc.1 // b
IL_000D: ldloc.0 // a
IL_000E: call System.Console.WriteLine
IL_0013: nop
IL_0014: ldloc.1 // b
IL_0015: call System.Console.WriteLine
IL_001A: nop
IL_001B: ret
特別要注意的是, "a" + "b" + "c"
和"def"
都導致完全相同的IL-換句話說,該工具足夠聰明,可以意識到"a" + "b" + "c"
與"abc"
完全相同。
現在,考慮以下代碼:
void Main()
{
var a = new StringBuilder();
a.Append("a");
a.Append("b");
a.Append("c");
string b = "def";
Console.WriteLine(a.ToString());
Console.WriteLine(b);
}
這將轉換為以下IL:
IL_0000: nop
IL_0001: newobj System.Text.StringBuilder..ctor
IL_0006: stloc.0 // a
IL_0007: ldloc.0 // a
IL_0008: ldstr "a"
IL_000D: callvirt System.Text.StringBuilder.Append
IL_0012: pop
IL_0013: ldloc.0 // a
IL_0014: ldstr "b"
IL_0019: callvirt System.Text.StringBuilder.Append
IL_001E: pop
IL_001F: ldloc.0 // a
IL_0020: ldstr "c"
IL_0025: callvirt System.Text.StringBuilder.Append
IL_002A: pop
IL_002B: ldstr "def"
IL_0030: stloc.1 // b
IL_0031: ldloc.0 // a
IL_0032: callvirt System.Object.ToString
IL_0037: call System.Console.WriteLine
IL_003C: nop
IL_003D: ldloc.1 // b
IL_003E: call System.Console.WriteLine
IL_0043: nop
IL_0044: ret
這是25條指令,而不是12條指令-換句話說,所謂的“更好”的代碼實際上導致了兩倍以上的IL和更大的內存消耗。
話雖如此,只需使用文字const string
(正如其他答案中已經指出的那樣)。
除非他們打算以后再向字符串中添加更多內容,否則在此處返回StringBuilder也很奇怪。 如果他們不這樣做,則應該返回一個字符串。 或者,在這種情況下,就像@David Browne指出的那樣,字符串常量會更好。
這一點可能更具爭議性,但是將其設置為屬性而不是公共常量是沒有意義的,並且只會增加不必要的開銷。 屬性最終是方法調用的語法糖,而const string
允許編譯器在編譯時進行文本替換,而不必進行運行時方法調用。
TL; DR僅使用const string
會更有效,因為示例中顯示的代碼會強制您的程序在運行時執行一些工作,而這些工作可以在編譯時輕松完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.