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