簡體   English   中英

使用StringBuilder獲取C#中的常量字符串?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM