【问题标题】:C# Creating new instance or Overwrite?C# 创建新实例还是覆盖?
【发布时间】:2020-05-11 12:30:57
【问题描述】:

我正在使用 SQL Server 数据库创建一个 C# Winform 应用程序,我以任何形式在 Form Class 中声明了一个 SqlCONnection 和一个 SqlCommand ,但我在需要时开始在每个方法中进行初始化。 这是我的代码:

    public partial class DrinkIncomeForm : Form
    {

        #region Class Variables
        private string conString;
        private string queryP1;
        private string queryP2;
        private SqlConnection con;
        private SqlCommand cmd;
        private SqlDataAdapter myAdapter;
        private SqlDataReader myReader;
        private DataTable drinksIncomeTable;
        #endregion

        public DrinkIncomeForm()
        {
            InitializeComponent();
        }
         private void DrinkIncomeForm_Load(object sender, EventArgs e)
        {
            conString = System.Configuration.ConfigurationManager.ConnectionStrings["MyGymConString"].ConnectionString;
            LoadDrinksCombo();
            LoadCashierCombo();
            DrinkComBox.SelectedIndex = 0;
            CashierComBox.SelectedIndex = 0;
            LoadDrinksIncomeDGV();
        }
        private void DrinkComBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadDrinksIncomeDGV();
        }

        private void CashierComBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadDrinksIncomeDGV();
        }
        private void LoadDrinksIncomeDGV()
        {
            con = new SqlConnection(conString);
            cmd = new SqlCommand();
            cmd.Connection = con;
            queryP1 = "select TransID, DrinkName, Quantity, Price, Offer, format(TransDate, 'dd/MM/yyyy hh:mm:ss')as TransDate, Cashier  from tblDrinksIncome ";
            queryP2 = " where 1=1 ";
            try
            {
                con.Open();
                cmd.Parameters.Clear();
                if(DrinkComBox.SelectedIndex >0)
                {
                    queryP2 += " AND DrinkName=@drinkname";
                    cmd.Parameters.AddWithValue("@drinkname", DrinkComBox.SelectedItem.ToString());
                }
                if (CashierComBox.SelectedIndex >0)
                {
                    queryP2 += " AND Cashier=@cashier";
                    cmd.Parameters.AddWithValue("@cashier", CashierComBox.SelectedItem.ToString());
                }
                cmd.CommandText = "" + queryP1 + queryP2;
                myAdapter = new SqlDataAdapter(cmd);
                drinksIncomeTable = new DataTable();
                myAdapter.Fill(drinksIncomeTable);
                DrinksIncomeDGV.DataSource = drinksIncomeTable;
                con.Close();
            }
            catch
            {
                con.Close();
                MessageBox.Show("Database Error.");
            }
        }
    }

正如您在每次用户从 ComboBoxes(Filters) 中选择时看到的那样,都会创建新实例。 我的问题是这对内存和性能有不良影响,如果是这样,更好的方法是什么? 谢谢:)

【问题讨论】:

  • 什么实例?即与您有关的事情是什么?实际上,这对于不是内循环数据处理场景的任何事物都不太可能成为问题。由于这似乎是 UI 绑定的,我什至不会看它 - 与正在发生的其他事情相比,这将是无关紧要的。可以优化吗?当然。有关系吗?可能至少不会。如果您想知道:测量它。如果它确实很重要,那么它可能意味着您向用户展示了太多有用的数据,所以:显示更少的数据!
  • 如果它确实很重要,我要说的第一件事是:“停止使用DataTable”。它对提高效率没有任何帮助。
  • 我很关心 (DataTable,SqlConnection,SqlCommand) 的实例。每次用户更改过滤器时,函数 LoadProductsIncome() 都会创建新实例,而我不知道旧实例会发生什么!我可以用什么来代替 DataTable ?
  • 一些 POCO TList<T> 现在通常是一个安全的赌注 - 即 List<Customer>List<Order> 或其他;也许看看“Dapper”如何在不自己编写代码的情况下实际填充它
  • 不要在每次调用时都创建new SqlConnection,使用单例模式或在表单打开时保持连接打开。每次都创建一个new SqlCommand 就可以了。

标签: c# performance memory instance


【解决方案1】:

它在性能上可能没有什么降级,但它是很好的设计。

但您不应将连接存储在成员变量中。但仅限于局部变量。最好是using(var s = new SqlConnection(..))。这样,您可以确保 Connection 在方法结束时被 Disposed,并且对它的任何引用都应该丢失,因此它可以被垃圾收集。 SqlCommand 也是如此。

所以你唯一的严重错误是不调用Dispose,你只调用Close

【讨论】:

  • "但是您不应该将连接存储在成员变量中。而只能存储在局部变量中。" - 这是高度上下文和主观的;根据场景,这两种方法都有效。当然,如果你每次都new,那么我100% 支持你(实例字段只有在被重用时才有意义)。同意命令,但是:我可能会说,如果你直接接触命令 API,那么你做错了 :)
  • @MarcGravell 好,你说得更准确。保持连接打开与否实际上取决于上下文。对于性能问题:每次一个新的都比较慢。只是想指出,您必须在性能与软件架构上做出妥协。如果你意识到这一点,一切都很好。如果您采用异步方式,则每个线程(通常是每个方法)一个连接是更安全的方式。
  • 如果你使用异步,你需要停止考虑线程 :) 但是,从根本上说:无论你使用同步还是异步,连接的并发共享都会被破坏;所以同意如果你要并发,你想要范围连接 - 我只是不认为同步与异步是重要的事情
  • 是的,我担心旧实例会发生什么,我不确定它是否会被收集!现在在 Close() 之后调用 Dispose() 会有意义吗?
  • 这不是一个明确的决定,是否保持连接打开更好。但至少,为了改进您当前的解决方案,请调用 dispose,并且不要将连接存储在您的私有字段中!只要被存储,它就不会被垃圾回收。
猜你喜欢
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 2013-09-04
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多