Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.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# SqlConnection SqlCommand SqlDataReader IDisposable_C#_.net_Sql Server_Ado.net - Fatal编程技术网

C# SqlConnection SqlCommand SqlDataReader IDisposable

C# SqlConnection SqlCommand SqlDataReader IDisposable,c#,.net,sql-server,ado.net,C#,.net,Sql Server,Ado.net,SqlConnection、SqlCommand和SqlDataReader都实现了IDisposable接口。我读到了一个最佳实践,即始终使用块将IDisposables包装到中 因此,我查询数据的常见场景看起来是这样的(在更大的上下文中,像linq2sql这样的映射工具当然是合适的,但假设我们想在这里使用这种方法): 这是正确的方法还是被认为是过度的?我有点不确定使用块的嵌套的这一级别,但我当然希望以正确的方式进行嵌套。 谢谢 我认为处理SqlCommand没有任何意义。但是,应该丢弃Sql

SqlConnection
SqlCommand
SqlDataReader
都实现了
IDisposable
接口。我读到了一个最佳实践,即始终使用块将
IDisposables
包装到

因此,我查询数据的常见场景看起来是这样的(在更大的上下文中,像linq2sql这样的映射工具当然是合适的,但假设我们想在这里使用这种方法):

这是正确的方法还是被认为是过度的?我有点不确定使用
块的嵌套
的这一级别,但我当然希望以正确的方式进行嵌套。

谢谢

我认为处理
SqlCommand
没有任何意义。但是,应该丢弃
SqlConnection
SqlDataReader

SqlConnection
,因为它在超出范围时不会自动关闭

SqlDataReader
可以使
SqlConnection
一直忙到读卡器关闭


甚至MSDN示例也没有处理
SqlCommand

我不是专家,但我知道使用会转换为try/finally块。也许您可以将SqlConnection、SqlCommand和SqlDataReader包装成一个独特的try/finally块

try {
     // code here with SqlConnection, SqlCommand and SqlDataReader
}
finally
{
  // Dispose call on SqlConnection, SqlCommand and SqlDataReader
 }

这是100%正确的方法。如果类利用了
IDisposable
,则应使用
语句将其包装在
中,以确保调用
Dispose()
方法。此外,与外部技术(不受管理)的通信,如SQL Server,也不应掉以轻心。
SqlCommand
对象实现了
IDisposable
,理由很充分。下面的代码是
SqlCommand
对象的
Dispose()
方法:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._cachedMetaData = null;
    }
    base.Dispose(disposing);
}

正如您所看到的,它正在释放对
\u cachedMetaData
对象的引用,以便它也可以被清除。

是的,这是正确的。你可以在嵌套语句中漏掉大括号,因为它们是一条语句,但我认为这不会增加可读性。

这并不是过分。使用
块的
是一种良好的做法,因为它可以确保调用对象的
Dispose()
方法,即使抛出异常也是如此

不过,这种东西有个名字。它叫代码糖。因此:

using (foo bar = new foo()) { //...snip }
是以下各项的简写代码:

foo bar = null;
Exception error = null;
try {
    bar = new foo();
    // ...snip
}
catch (Exception ex) {
    error = ex;
}
finally {
    if (bar != null) bar.Dispose();
    if (error != null) throw error;
}
任何一种形式都是平等的,它们只是写同一件事的不同方式。换句话说,
for
while
之间的区别是相同的:它们基本上做相同的事情,但使用方式不同

使用
是首选,因为它可以使代码更短、更可读,并为您自动处理。至于你是否应该使用它,不要听那些说你应该一直做某事的人说。当然,这是一个很好的实践,但是知道什么时候使用、为什么使用和不使用的好处和后果比人们说你应该做的事情更有价值


Edit:Eren的答案有一个例子,说明您不希望使用
读卡器的
,这是正确的方法,如果您使用读卡器的话。有时,您需要读卡器保持打开状态(可能您的方法会返回它),因此它无法立即处理读卡器。在这些情况下,ExecuteReader的过载可以帮助您:

var cn = new SqlConnection("myConnectionstring");
var cm = new SqlCommand("myQuery", cn);
var reader = cm.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
这将保持连接和读卡器打开。一旦读卡器关闭/释放,它也将关闭(并释放)连接

using(var reader = GetReader()) //which includes the code above
{
   ...
} // reader is disposed, and so is the connection.

您可以使用以下排版方式使代码更靠近左侧:

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
using (SqlCommand cm = new SqlCommand("myQuery", cn))
using (SqlDataReader reader = cm.ExecuteReader())
{
     // read values from reader object
     return myReadValues;
}

正如其他人已经指出的那样,使用三个嵌套的
块是正确的。

不是我把你记下来的,但不要尝试这样做。这是不等价的,如果异常像筛子一样泄漏,可能会引发更多的异常,那么编译器应该会发出一堆警告。@TonyHopkinson我回答只是为了得到反馈。你能进一步解释为什么它不是等价的吗?非常感谢你!如果sql连接引发异常。最后执行,然后在sqlcommand上得到一个空引用异常。为了绕开这一关,你必须测试零分,嗯?它实现了Idisposable,所以它将被处理掉。在GC启动之前,为什么要让它保持浮动状态呢?这是一种被广泛接受的最佳实践,可以处理任何实现
IDisposable
的类实例。问题不在于为什么要处理
SqlCommand
,而在于为什么不?我只是指出,它实际上并不比处理任何其他非关键的东西更重要@TonyHopkinson,您是否在创建的每个对象都超出范围后运行GC?不因为没有意义。Dispose还使用时钟周期。您应该反对垃圾收集,或者根本不反对垃圾收集。有些类(如SqlCommand、DataTable)实现IDisposable,但它们所做的只是将私有引用设置为null,如果包含的实例超出范围,则该类无效。我通常会使用dispose-SqlCommand,但严格来说,这个答案是正确的,省略dispose不会产生任何负面影响。同意Evan Lewis的观点,不,我不运行GC,除非在边缘情况下。记住处理比记住几个你可以不处理的案例要重要得多。更不用说它为您提供的固有范围。感谢您的回答,特别是关于
SqlCommands
的dispose的详细信息-正是我要查找的信息@Chips_100,我很高兴能帮上忙!仅供参考,“using”是try-->finally块的语法糖,finally调用在该块中进行处置。不要这样做
using (SqlConnection cn = new SqlConnection("myConnectionstring"))
using (SqlCommand cm = new SqlCommand("myQuery", cn))
using (SqlDataReader reader = cm.ExecuteReader())
{
     // read values from reader object
     return myReadValues;
}