Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何重构此方法?_C# - Fatal编程技术网

C# 如何重构此方法?

C# 如何重构此方法?,c#,C#,它工作正常,但我想把它缩短,以便更容易理解。如何重构它?为每个命令(在if语句中)创建字符串(或字符串数组),如果字符串不为空,则随后运行sql [注] 在任何情况下都不会关闭连接 [/note]为了让它更容易理解,您可能需要重构它,以便更容易测试 在这种情况下,可能需要去掉ConnectionClass单例(而是使用IoC并注入连接工厂)和MessageBox(例如,抛出异常并让周围的代码确定如何显示此消息)您可以使用参数,当您不想更新字段时,可以将其设置为NULL: private void

它工作正常,但我想把它缩短,以便更容易理解。如何重构它?

为每个命令(在
if
语句中)创建字符串(或字符串数组),如果字符串不为空,则随后运行sql

[注]
在任何情况下都不会关闭连接

[/note]

为了让它更容易理解,您可能需要重构它,以便更容易测试


在这种情况下,可能需要去掉
ConnectionClass
单例(而是使用IoC并注入连接工厂)和MessageBox(例如,抛出异常并让周围的代码确定如何显示此消息)

您可以使用参数,当您不想更新字段时,可以将其设置为
NULL

private void Update_Record_Click(object sender, EventArgs e)  
    {  
        ConnectionClass.OpenConnection();  

        if (textBox4.Text == "" && textBox2.Text == "")  
        {  
            MessageBox.Show("No value entred for update.");  
        }  
        else if (textBox4.Text != "" && textBox2.Text != "")  
        {  
            SqlCommand cmd = new SqlCommand("update medicinerecord set quantity='" + textBox2.Text + "' where productid='"+comboBox1.Text+"'", ConnectionClass.OpenConnection());  
            cmd.ExecuteNonQuery();  

            cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
            cmd.ExecuteNonQuery();
            ConnectionClass.CloseConnection();
        }
        else if (textBox2.Text != "")
        {
            SqlCommand cmd = new SqlCommand("update myrecord set quantity='" + textBox2.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
            cmd.ExecuteNonQuery();
            ConnectionClass.CloseConnection();
        }
        else if (textBox4.Text != "")
        {
            SqlCommand cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
            cmd.ExecuteNonQuery();
            ConnectionClass.CloseConnection();
        }  
}  
然后,根据文本字段,您可以使用
command.Parameters.AddWithValue
方法执行单个命令。对
NULL
使用
DBNull.Value
。即使不更改结构,也应该这样做以防止SQL注入攻击

干杯,马蒂亚斯你可以看到

UPDATE myrecord SET price = ISNULL(@price, price) -- MSSQL
是reduntant,那么为什么不将其移动到最后一个
之后呢?如果
作用域不在,则将其移动。

使代码“小”可能不是使其可读或“易于理解”的最佳方法。我发现更简洁的代码比具有高质量变量、方法、属性、类名等的代码更难理解

我认为更严重的问题不是代码的大小,而是您容易受到SQL注入攻击这一事实

这是我很久以前写的一篇文章,你可能会发现它很有用:

我希望这能有所帮助。

免责声明:根据Darin的建议,我稍微改变了他最初的解决方案。布朗医生

这段代码很大这一事实是最小的问题。在这里,SQL注入有更大的问题。您应该使用参数化查询来避免这种情况

因此,我首先将数据访问逻辑外部化为一个单独的方法:

 cmd.ExecuteNonQuery();                 
    ConnectionClass.CloseConnection();  
然后:

public void UpdateMedicineRecordQuantity(string tableName, string attributeName, string productId, string attributeValue)
{
    using (var conn = new SqlConnection("YOUR ConnectionString HERE"))
    using (var cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = "UPDATE " + tableName + "SET " + attributeName+ " = @attributeValue where productid = @productid";
        cmd.Parameters.AddWithValue("@attributeValue", attributeValue);
        cmd.Parameters.AddWithValue("@productid", productId);
        cmd.ExecuteNonQuery();
    }
}
使用“tableName”和“attributeName”作为SQL的动态部分没有安全问题,只要您不让用户为这两个参数提供输入


您可以继续在其他情况下重用此方法。

为什么不再创建一个方法:

string productId = comboBox1.Text;
string quantity = textBox2.Text;
UpdateMedicineRecordQuantity("medicinerecord", "quantity", productId, quantity);

您的代码正在等待SQL注入。请注意“ol Johnny Tables”。

我对您的代码进行了一些简化和优化,并添加了一些注释

void ExecuteCommand(string sql)
{
           SqlCommand cmd = new SqlCommand(sql);  
            cmd.ExecuteNonQuery();
            ConnectionClass.CloseConnection();
}
  • 如果只执行一行代码,可以通过删除条件语句(如
    if
    )上的大括号立即简化代码。我为你做了这件事
  • 在未首先转义任何用户输入的变量之前,不要使用字符串连接构建SQL语句。例如,
    更新我的记录集价格='“+textbox4.Text+”
    。。至少应该是
    updatemyrecord set price='“+textbox4.Text.Replace(“'”,“”)
    。以避免可能的攻击
  • 与其测试
    .Text==“”
    ,通常更倾向于使用或在.NET 4上覆盖空字符串和空字符串
  • 替换
    var
    的任何显式类型的数据类型
  • 最后,您可以简化此代码,方法是在验证未满足时立即返回(如前几行所示),并在验证发生后在此方法的顶部和底部指定一个
    OpenConnection()
    CloseConnection()
  • 还修复了拼写错误!:)

    类似于
    if的语句(textBox4.Text==”&&textBox2.Text==”)
    如果你不了解应用程序的特定部分在做什么,那就没有任何意义。在这种情况下,它们似乎每个代表一个值,并且至少其中一个应该包含合法操作的内容。研究SQL语句表明
    textBox2
    是一个数量,而
    textBox4是一个价格。首先要将这些控件名称更改为更有意义的名称

    其次,我将检查包装成具有更多描述性名称的方法:

    private void Update_Record_Click(object sender, EventArgs e)  
    {  
        if (textBox4.Text == "" && textBox2.Text == "")
        {
            MessageBox.Show("No value entered for update.");  
            return;
        }
        ConnectionClass.OpenConnection();  
    
        var cmd = new SqlCommand("update medicinerecord set quantity='" + textBox2.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
        cmd.ExecuteNonQuery();  
    
        cmd = null;
        if (textBox2.Text != "")
            cmd = new SqlCommand("update myrecord set quantity='" + textBox2.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
        else if (textBox4.Text != "")
            cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
    
        if (cmd != null) cmd.ExecuteNonQuery();
        ConnectionClass.CloseConnection();
    }  
    
    然后可以将if块重写为:

    private bool HasPriceValue()
    {
        return !string.IsNullOrEmpty(textBox4.Text);
    }
    
    private bool HasQuantityValue()
    {
        return !string.IsNullOrEmpty(textBox2.Text);
    }
    

    通过这种方式,您不必在代码中重复SQL查询,阅读代码并理解其功能相当容易。下一步是重写SQL查询以使用参数而不是串联字符串(这会打开代码进行SQL注入攻击)使用你的编辑器的缩小特性使代码变小……我编辑了这个问题使它更清晰。如果你想提高别人对它的理解,你也可以考虑给你的控件有意义的ID。我认为OP意味着更短,即更简洁。你也可以使用K&R风格的括号而不是BSD。这样可以节省哟。u每个块都有一行。这应该扩展以回答原始问题:“UpdateMedicinerRecordQuantity”方法应该得到两个名为“tableName”和“columnName”的附加参数,使其在原始代码的所有四个位置都可重用。否则,我打赌OP会去复制/粘贴/修改你的例子四次以上。@Doc Brown,请随意编辑我的答案并包含此重构。谢谢你的帮助,下次我会记住控件的名称。我真的很担心。还有一件事,它是一个简单的窗口应用程序,所有操作都将在后台运行,那么它如何受到SQLInjection的攻击。@avirk:用户可以在其中一个文本框中输入精心编制的SQL命令,并在数据库中执行任何类型的操作(包括删除表)。请看这里以获得进一步的解释:那么我如何才能阻止我的应用程序使用它。@avirk,看看哪个应用程序使用参数化查询,这就是如何阻止它的。在这幅漫画中,他们称他为Bobby Tables,但是同一件事
    if (!HasPriceValue() && !HasQuantityValue())
    { 
        MessageBox.Show("No value entred for update."); 
    }
    else
    {
        ConnectionClass.OpenConnection(); 
        if (HasQuantityValue())  
        {  
            SqlCommand cmd = new SqlCommand("update medicinerecord set quantity='" + textBox2.Text + "' where productid='"+comboBox1.Text+"'", ConnectionClass.OpenConnection());  
            cmd.ExecuteNonQuery();  
        }
        if (HasPriceValue())
        {
            SqlCommand cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
            cmd.ExecuteNonQuery();
        }
        ConnectionClass.CloseConnection();
    }