【问题标题】:What is the purpose of the string builder here?字符串生成器的目的是什么?
【发布时间】:2012-09-12 19:54:53
【问题描述】:

我只做过 C++ 和一些 C#,而且我是 MySQL 新手,我不明白这里的字符串生成器的目的。

此代码是用于从网页中提取数据并使用书签将其插入现有 Word 文件的程序的一部分。

我的代码

using System.Collections.Generic;
using System.Configuration;
using System.Text;
using MySql.Data.MySqlClient;

namespace ARExtractionLibrary
{
    public class DataExtractor
    {
        #region Attributes
        private string _databaseConfig = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
        private const int AR_TRACKER_ID = 10;
        private const int AR_NUMBER_ID = 3;
        #endregion

        #region Methods
        public Dictionary<string, Field> GetFieldData(int TicketID)
        {
            MySqlConnection sqlConnection = new MySqlConnection(_databaseConfig);
            Dictionary<string, Field> fieldsDictionary = new Dictionary<string, Field>();

            StringBuilder queryDefaultFields = new StringBuilder();
            queryDefaultFields.Append("SELECT issues.id AS TicketID, issues.subject, issues.description, ");
            queryDefaultFields.Append(" CONCAT(users.firstname,' ', users.lastname) as Author");
            queryDefaultFields.Append(" FROM issues LEFT JOIN users ON users.id =issues.author_id");
            queryDefaultFields.Append("  WHERE issues.id = @TicketID");

            StringBuilder queryCustomFields = new StringBuilder();
            queryCustomFields.Append("SELECT custom_fields.name, custom_fields.field_format, CONCAT(users.firstname,' ',users.lastname) AS value");
            queryCustomFields.Append(" FROM custom_values");
            queryCustomFields.Append(" LEFT JOIN custom_fields ON custom_values.custom_field_id = custom_fields.id");
            queryCustomFields.Append(" JOIN users ON custom_values.value = users.id");
            queryCustomFields.Append(" WHERE custom_values.customized_id = @TicketId");
            queryCustomFields.Append(" AND field_format = 'user'");
            queryCustomFields.Append(" UNION");
            queryCustomFields.Append(" SELECT custom_fields.name, custom_fields.field_format, custom_values.value");
            queryCustomFields.Append(" FROM custom_values");
            queryCustomFields.Append(" LEFT JOIN custom_fields ON custom_values.custom_field_id = custom_fields.id");
            queryCustomFields.Append(" WHERE custom_values.customized_id = @TicketId");
            queryCustomFields.Append(" AND field_format <> 'user'");

            sqlConnection.Open();

            //First query
            MySqlCommand sqlCommand = null;
            sqlCommand = new MySqlCommand(queryDefaultFields.ToString(), sqlConnection);
            sqlCommand.Parameters.AddWithValue("@TicketId", TicketID);

            MySqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
            while (sqlDataReader.Read())
            {
                Field subject = new Field("Subject", sqlDataReader["subject"].ToString());
                fieldsDictionary.Add(subject.Name, subject);

                Field description = new Field("Description", sqlDataReader["description"].ToString());
                fieldsDictionary.Add(description.Name, description);

                Field ticketID = new Field("TicketID", sqlDataReader["TicketID"].ToString());
                fieldsDictionary.Add(ticketID.Name, ticketID);

                Field author = new Field("Author", sqlDataReader["Author"].ToString());
                fieldsDictionary.Add(author.Name, author);
            }
            sqlDataReader.Close();

            //Second query
            sqlCommand = new MySqlCommand(queryCustomFields.ToString(), sqlConnection);
            sqlCommand.Parameters.AddWithValue("@TicketId", TicketID);
            sqlDataReader = sqlCommand.ExecuteReader();

            while (sqlDataReader.Read())
            {
                string fieldName = sqlDataReader["name"].ToString();
                string fieldValue = sqlDataReader["value"].ToString();
                string fieldFormat = sqlDataReader["field_format"].ToString();

                if (fieldsDictionary.ContainsKey(fieldName))
                {
                    fieldsDictionary[fieldName].Values.Add(fieldValue);
                }

                else
                {
                    Field localField = new Field(fieldName, fieldValue, fieldFormat);
                    fieldsDictionary.Add(localField.Name, localField);
                }
            }
            sqlDataReader.Close();
            sqlConnection.Close();

            return fieldsDictionary;
        }

        public Dictionary<int, string> GetARs()
        {
            Dictionary<int, string> ARDictionary = new Dictionary<int, string>();
            MySqlConnection sqlConnection = new MySqlConnection(_databaseConfig);
            StringBuilder sqlCommandIsAR = new StringBuilder();
            sqlCommandIsAR.Append("SELECT issues.id AS TicketID, issues.tracker_id AS Tracker, issues.subject AS Subject, custom_values.custom_field_id, custom_values.value");
            sqlCommandIsAR.Append(" FROM issues LEFT JOIN Custom_values ON custom_values.customized_id = issues.id ");
            sqlCommandIsAR.Append(" WHERE tracker_id = @IsAR AND custom_field_id = @IsARNumber ");

            sqlConnection.Open();

            MySqlCommand commandGetARs = new MySqlCommand(sqlCommandIsAR.ToString(), sqlConnection);
            commandGetARs.Parameters.AddWithValue("@IsAR", AR_TRACKER_ID);
            commandGetARs.Parameters.AddWithValue("@IsARNumber", AR_NUMBER_ID);
            MySqlDataReader sqlDataReader = null;
            sqlDataReader = commandGetARs.ExecuteReader();

            while (sqlDataReader.Read())
            {
                string DictionaryValue = sqlDataReader["TicketID"].ToString() + " - " + sqlDataReader["Subject"].ToString();

                if (sqlDataReader["value"].ToString().Length != 0)
                {
                    DictionaryValue += " [" + sqlDataReader["value"].ToString() + "]";
                }

                int key = int.Parse(sqlDataReader["TicketID"].ToString());
                ARDictionary.Add(key, DictionaryValue);
            }

            sqlDataReader.Close();
            sqlConnection.Close();

            return ARDictionary;
        }

        #endregion
    }
}

【问题讨论】:

  • 在这种特殊情况下 StringBuilder 什么都不提供;它只会让代码运行得更慢。
  • 我现在明白了,但是 MySQL 对所有这些字符串做了什么?这是我不明白的。

标签: c# .net mysql


【解决方案1】:

StringBuilder 避免每次添加字符串时都必须重新创建字符串。在 C# 中使用 String 类意味着您使用的是不可变对象,但 StringBuilder 在大多数情况下要快得多,因为它不必每次附加到它时都创建一个新字符串。

因此,一般而言,如果您多次附加到字符串,StringBuilder 将比仅执行 str += "text to append"(其中 str 是 String)更有效。

这里有一些注意事项需要注意,请参阅this 答案。

【讨论】:

  • downvoter,想解释一下为什么,而不是只是打了就跑?
【解决方案2】:

为了提高性能,您将添加大量字符串。众所周知,即使是 reference 类型 string 的行为也类似于 value 类型。

因此,在每次添加字符串时,都会分配一个 new 字符串对象。

string s = "hello"; 
s += " world"; //NEW STRING OBJECT ALLOCATED 

如果是StringBuilder,则没有任何新的分配,只是追加到它的末尾。

StringBuilder queryDefaultFields = new StringBuilder();
queryDefaultFields.Append("hello");   //THE SAME queryDefaultFields OBJECT
queryDefaultFields.Append(" world");  //THE SAME queryDefaultFields OBJECT

【讨论】:

  • String 的行为不像值类型。它的行为类似于引用类型,因为它是一个。它是不可变的,但可变性与它是值类型还是引用类型完全无关。任何一种类型都可以是可变的或不可变的。
  • @Servy:我希望这个概念:“表现 like 值类型”是一个明确的、具有不变性的概念。
  • 但值类型并非都是不可变的。首先,不可变甚至不是值类型的属性。除此之外,作为值类型意味着变量实际上保存了该值,而不是存储在其他地方的实际信息。这是值类型的唯一且唯一的实际特征。其余的(实际属性中,不变性不是其中之一)本质上是副作用。值类型与此无关。哦,你甚至没有讨论提供的代码 sn-p 或提到这是在你的答案中不正确地使用 StringBuilder
  • 阅读接受的答案将是一个开始。您必须询问的事实意味着您要么没有阅读代码 sn-p,要么您实际上不知道何时应该或不应该使用StringBuilder,这意味着您无权回答这样的问题。这里正在构建的字符串完全是一个编译时间常数,而不是由许多直到运行时才知道的串联构建的。
  • @Servy:问题询问为什么在这种情况下使用字符串生成器。很明显,代码倾向于连接字符串。所以我的回答是:为了加快连接速度,我可以进一步建议不要这样做,而是使用单个字符串常量,但缺少额外的建议,不会使我的 asnwer 无效。
【解决方案3】:

由于 StringBuilder 是可变的(与字符串相反),这意味着您可以在任何给定时间使用 Append(或 AppendLine)方法简单地向其添加数据,只要您有它的引用。

【讨论】:

    【解决方案4】:

    一般

    StringBuilder 允许您构建字符串,而无需在每次变异操作时为字符串的内容重新分配缓冲区(始终使用相同的缓冲区;仅当字符串扩展超出当前容量时才会重新分配)。这使得构建大字符串的整个过程更加高效。

    在这段代码中

    在这种情况下,根本没有动态构建字符串;字符串实际上是硬编码的。这里StringBuilder 完全没有意义;如果字符串是这样的硬编码文字,实际上性能会更好:

    var queryDefaultFields = @"SELECT issues.id AS TicketID, issues.subject, issues.description,
                               CONCAT(users.firstname,' ', users.lastname) as Author
                               FROM issues LEFT JOIN users ON users.id =issues.author_id
                               WHERE issues.id = @TicketID";
    

    我的猜测是,这段代码的作者要么误用了StringBuilder,因为他们记得读过“这样更快”,但从未真正理解为什么,或者犯了疏忽复制粘贴的罪行。

    【讨论】:

    • 这可能是代码作者之前使用了StringBuilderAppendFormat方法,因为这是创建SQL查询的常见做法(但不是完美的方法,因为此查询容易受到SQL注入)。但过了一段时间,他对这些值进行了硬编码,并用Append 方法替换了AppendFormat
    • @T_12:可能,但这只是你所说的另一种做错的方式。双重错误,我可能会补充。
    猜你喜欢
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多