StringBuilder线程安全

时间:2014-06-12 10:15:23

标签: c# ado.net thread-safety stringbuilder

我为SqlCommand编写了一个扩展方法来执行一批命令,我称之为ExecuteBatchNonQuery。这很好用。我已经更改为返回消息输出,为此我必须创建一个从InfoMessage调用的方法。它附加到一个我不得不制作静态的字符串构建器。我担心这个stringbuilder不是线程安全的。我必须使用静态,有什么方法可以让它保持线程安全,还是有替代方法?

internal static class SqlCommandHelper
{
    private static readonly StringBuilder StringBuilder = new StringBuilder();

    internal static string ExecuteBatchNonQuery(this SqlCommand cmd, string sql)
    {
        SqlConnection conn = cmd.Connection;
        conn.Open();
        conn.InfoMessage += MyConnectionInfoMessage;
        string sqlBatch = string.Empty;
        sql += "\nGO"; // make sure last batch is executed.
        StringBuilder.Clear();
        try
        {
            foreach (string line in sql.Split(new string[2] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (line.ToUpperInvariant().Trim() == "GO")
                {
                    cmd.CommandText = sqlBatch;
                    cmd.ExecuteNonQuery();
                    sqlBatch = string.Empty;
                }
                else
                {
                    sqlBatch += line + "\n";
                }
            }
        }
        finally
        {
            conn.Close();
        }
        return StringBuilder.ToString();
    }

    private static void MyConnectionInfoMessage(object sender, SqlInfoMessageEventArgs e)
    {
        StringBuilder.AppendLine(e.Message);
    }
}

1 个答案:

答案 0 :(得分:6)

您的StringBuilder应该是一个局部变量。您可以使用Lambda表达式来实现此目的:

internal static class SqlCommandHelper
{
    internal static string ExecuteBatchNonQuery(this SqlCommand cmd, string sql)
    {
        var sb = new StringBuilder(); 
        SqlConnection conn = cmd.Connection;
        conn.Open();
        conn.InfoMessage += (sender, e) => { sb.AppendLine(e.Message); };
        string sqlBatch = string.Empty;
        sql += "\nGO"; // make sure last batch is executed.
        sb.Clear();
        try
        {
            foreach (string line in sql.Split(new string[2] { "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries))
            {
                if (line.ToUpperInvariant().Trim() == "GO")
                {
                    cmd.CommandText = sqlBatch;
                    cmd.ExecuteNonQuery();
                    sqlBatch = string.Empty;
                }
                else
                {
                    sqlBatch += line + "\n";
                }
            }
        }
        finally
        {
            conn.Close();
        }
        return sb.ToString();
    }
}