Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.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语言中处理相互引用的多个对象#_C#_Sql_.net - Fatal编程技术网

C# 在c语言中处理相互引用的多个对象#

C# 在c语言中处理相互引用的多个对象#,c#,sql,.net,C#,Sql,.net,好的,我已经搜索了“类似”的主题,但仍然没有找到我将要问的问题的任何答案 我有一个函数,可以在System.Data.SqlClient命名空间下创建多个sql对象。我已经读到using语句在using块之后处理对象,但是声明的变量是只读的。我的函数重用了其中一些变量,因此我无法使用语句在中声明它们 为了清楚起见,这里是我的函数的主体。我应该对其他对象(命令、事务、读取器等)调用Dispose,还是将使用通过连接对象递归地处理它们?我应该如何处理这些对象 我对C#(我来自C/C++背景)还是新手

好的,我已经搜索了“类似”的主题,但仍然没有找到我将要问的问题的任何答案

我有一个函数,可以在System.Data.SqlClient命名空间下创建多个sql对象。我已经读到using语句在using块之后处理对象,但是声明的变量是只读的。我的函数重用了其中一些变量,因此我无法使用语句在中声明它们

为了清楚起见,这里是我的函数的主体。我应该对其他对象(命令、事务、读取器等)调用Dispose,还是将使用通过连接对象递归地处理它们?我应该如何处理这些对象

我对C#(我来自C/C++背景)还是新手,所以如果这个问题听起来很无知,请原谅我

public string SignIn(string userId, string password)
{
     SqlCommand sqlCommand = null;
     SqlTransaction sqlTransaction = null;
     string sessionId = "";

     using(SqlConnection sqlConnection = new SqlConnection Properties.Settings.Default.SessionManagerDBConnectionString))
     {
          try
          {
               sqlConnection.Open();

               sqlCommand = sqlConnection.CreateCommand();
               sqlCommand.CommandText = "GetUserByUserIdPassword";
               sqlCommand.CommandTimeout = 30;
               sqlCommand.CommandType = CommandType.StoredProcedure;
               SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
               parameterUserId.Value = userId;
               SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
               parameterPassword.Value = this.GetSHA256Hash(password);
               sqlTransaction = sqlConnection.BeginTransaction("SampleTransaction");

               // more database activity, execute command, store results in datareader
               sqlTransaction.Commit();
               sqlConnection.Close();
          }
          catch (SqlException ex)
          {
               if(sqlTransaction != null)
                    sqlTransaction.Rollback();
               MessageBox.Show(ex.Number + ":" + ex.Message, ex.Server + ":" + ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
          }
     }
     return sessionId;
}

我试图再次搜索类似的问题,并找到了一些更接近的答案

我想我应该在try-catch中添加一个finally子句,并为我创建的所有sql对象调用几个Dispose方法。我希望这就足够了,或者有没有推荐的方式

finally
{
     if(sqlCommand != null)
          sqlCommand.Dispose();
     if(sqlTransaction != null)
          sqlTransaction.Dispose();
     ...
}

我尝试在其中一个sqlCommand对象的try-catch块中放置一个using语句,但是如果抛出异常时该部分代码中止,则执行跳到catch部分。使用时不会处理该sqlCommand对象

try
{
     ...
     using(sqlCommand = sqlConnection.CreateCommand())
     {
          sqlCommand.CommandText = "GetUserByUserIdPassword2";
          sqlCommand.CommandTimeout = 30;
          sqlCommand.CommandType = CommandType.StoredProcedure;
          SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
          parameterUserId.Value = userId;
          SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
          parameterPassword.Value = this.GetSHA256Hash(password);

          SqlDataReader reader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
          // throws exception, no stored procedure "GetUserByUserIdPassword2"
     }
     ...
}
catch() {}

// sqlCommand still accessible at this point because using above was "aborted".
将通过连接对象递归地处理它们

当然,
使用
SqlConnections
或其他ADO.NET对象一无所知。它只知道调用
Dispose
。无论被处置的对象做什么,都会发生什么

在这种情况下,处理
SqlConnection
也会处理与该连接相关联的所有读卡器和命令的资源。您只需要处理连接

我不知道这是否记录在MSDN上,但我通过反编译程序集知道。出于兼容性原因,他们永远无法更改此行为,因此可以安全地依赖它


通常,必须对实现
IDisposable
的任何对象调用dispose。此规则的例外情况是,当您确信不调用
Dispose
是安全的时。与本例类似。

如果对象实现了
IDisposable
,则使用
using
。如果出于某种原因需要创建一个新的
SqlCommand
,请使用块完成一个
,然后启动一个新命令。如果仍然需要访问第一个
SqlCommand


您可以重用
SqlCommand
对象,只要该命令没有打开
datareader
。因此,您可以创建一个
SqlCommand
,设置它的所有属性并执行它,然后重置它的所有属性并再次执行它,依此类推。这确实稍微节省了内存分配的成本,但我认为这也降低了代码的清晰度,因此只有在分析证明有必要时,我才会这样做。

在CSharp中,
使用是一个特殊的关键字,在代码中有不同的行为

如果将使用到代码页的顶部,那么使用C++作为C++的代码>包含或VB(以及其他一些脚本Langs)<代码>导入< /COD> < /P> 如果您使用

”编写了一个“
”,后面跟着一个paradensis,那么它就像CSharp的
Dispose()
方法的别名。。或< < C++ >代码> > Destructor tilda > <代码> > />代码> 关于
SQL连接
。。最好的方法是首先
Close()
连接(这样,连接仍然处于活动状态-实际上刚刚准备好使用-但为空..返回到连接池中等待新订单..),然后根据需要进行处置

如果仍然存在问题,并且怀疑调用
Dispose()
方法不足以释放资源

然后,您可以使用
垃圾收集器
Collect()
静态方法强制垃圾收集 但Microsoft不推荐这么多,因为它面临意外的垃圾收集问题(即,您收集表单,但需要该表单中的一些变量)

在用法示例中:

public void Dispose (bool ForceToCollect )
{
   if (ForceToCollect) 
               GC.Collect (0, GCCollectionMode.Forced );
}
Gc.Collect()
方法中,您可以设置使用第一个选项释放的数据内存组,其中int。如果您计划释放最后一个组的资源-表示最后创建的一组项,例如最后创建的表单实例及其所有子控件-则int应为0;在上次创建之前为1的应为1,依此类推


希望这有帮助。

我想我找到了答案

即使当抛出的异常跳过嵌套的using语句时,sqlCommand对象仍然可以在代码的底部访问,sqlCommand仍然会在稍后被释放。我通过实际为所述sqlCommand对象的已处理事件分配一个函数来测试这一点

try
{
     ...
     using(sqlCommand = sqlConnection.CreateCommand())
     {
          sqlCommand.CommandText = "GetUserByUserIdPassword2";
          sqlCommand.CommandTimeout = 30;
          sqlCommand.CommandType = CommandType.StoredProcedure;
          SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
          parameterUserId.Value = userId;
          SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
          parameterPassword.Value = this.GetSHA256Hash(password);

          SqlDataReader reader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
          // throws exception, no stored procedure "GetUserByUserIdPassword2"
     }
     ...
}
catch() {}

// sqlCommand still accessible at this point because using above was "aborted".
由于事务对象的要求,这里的代码与上面的代码略有不同。但逻辑基本相同

try
{
       using(sqlCommand = new SqlCommand("GetUserByUserIdPassword2", sqlConnection, sqlTransaction))
       {
              sqlCommand.CommandTimeout = 15;
              sqlCommand.CommandType = CommandType.StoredProcedure;
              SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
              parameterUserId.Value = userId;
              SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
              parameterPassword.Value = this.GetSHA256Hash(password);

              sqlCommand.Disposed += new System.EventHandler(this.sqlCommand_Disposed);

              SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
              // exception thrown, no sored proc "GetUserByUserIdPassword2"
              sqlDataReader.Close();
       }
}
catch(...) {}

...

private void sqlCommand_Disposed(object sender, EventArgs e)
{
     MessageBox.Show("sqlCommand has been disposed");
}
因此,基本上,即使嵌套的using语句被try块中抛出的异常“中止”,并且执行被跳到catch块,在函数退出后(或者当变量超出范围时),仍然会为该对象调用Dispose方法


我假设任何数量的嵌套using语句的行为都是相同的。

请包含所有相关代码,例如:
我有一个函数,可以在System.Data.SqlClient命名空间下创建多个sql对象。
。另外,
using
语句将只处理您在语句中引用的对象。可以安全地假设任何类从
IDisposable