在按值与引用构造数据读取器时配置数据读取器

Posted

技术标签:

【中文标题】在按值与引用构造数据读取器时配置数据读取器【英文标题】:Disposing a data reader when constructing it by value vs reference 【发布时间】:2011-07-02 15:13:13 【问题描述】:

关于当使用ref 与 var 在类中构造数据读取器时,何时真正发布数据读取器的新手问题。我今天一直在测试它,结果让我有点困惑——希望能在我的脑海中弄清楚这一点。

我有一个类,用于通过 ODBC 从众多远程服务器获取数据,但我需要限制对我所连接的每台服务器打开的 ODBC 连接数 - 所以我在正确处理数据读取器时要小心当我在打开另一个之前完成了它们。简短的版本是我有一个名为 FillDataReader 的方法,它接受一个数据读取器对象,并根据您的查询填充它并将其传回。

如果我使用ref 传递它并从调用方处理数据读取器,一切都很好。连接立即释放,客户端可以在不烧掉连接的情况下获得另一个数据读取器。但是,如果我按值传递,则不会释放资源,并且如果我从客户端打开另一个数据读取器,我现在有两个到该服务器的连接。

从概念上讲,我明白了不同之处——ref 只使用了一个地址,因为它传递了一个“指向指针的指针”,并且 dispose 释放了该资源。好的,但是即使通过值传递并在客户端进行显式处置,究竟是什么持有资源?我宁愿在这里传递值,这样我就可以在客户端使用漂亮的using 构造,但更重要的是我想更好地了解这里发生了什么。简而言之,这就是它的样子

[数据库提取类]

public bool FillDataReader(string pQueryString, ref System.Data.Odbc.OdbcDataReader pDataReader, out string pErrorReason)
        
(uses a connection object that’s been established at class construction time and stays up all the time)
...
            try
            
                pDataReader = _Command.ExecuteReader();
            
...
         

[Calling class]

strSQL = "SELECT Alias, ObjectID, FROM vw_GlobalUser";
               if (ServerList[currentServer].DatabaseFunctions.FillDataReader(strSQL, ref drTemp, false, out strErrorReason) == false)
               ….

    drTemp.Dispose();

(at this point the connection is released to the server)

但是,如果我在调用类中的 Dispose 点取出ref,则连接不会被释放。它最终会消失,但我需要它立即消失(因此需要处理)。

那么 DB fetch 类中的填充函数是否以某种方式挂在对堆上分配空间的引用上?我不确定我理解为什么会这样——理解它使用堆栈上数据读取器的地址的另一个副本来引用堆上的数据读取器对象,但是当它超出范围时,它不是被释放了吗?也许我需要更多的咖啡……

【问题讨论】:

【参考方案1】:

由于您的调用代码需要接收引用以释放对象,因此您确实需要ref(或out)。否则,参数只会传递给方法,而不是返回,因此drTemp 不会被FillDataReader 方法中创建的数据读取器更新。

请注意,您可能希望按如下方式更改签名以使意图更明确:

public Result TryGetDataReader(string pQueryString, out System.Data.Odbc.OdbcDataReader pDataReader)

我建议的更改:

引入了带有“Try”的命名约定,这对于这种类型的方法很常见 将 pDataReader 设为 out,因为在调用方法时不需要对其进行初始化 引入了一个“Result”类型,它应该携带成功信息和错误信息(如果有的话)

【讨论】:

谢谢 - 让它出来是有道理的,结果对象的使用也是如此(我的待办事项清单上已经有了) - 不确定我是否理解关于命名约定的评论“尝试"虽然 不抛出异常但“尝试”执行操作的方法通常以这种方式命名。很好的例子是Dictionary.TryGetValue() 和所有TryParse() 简单类型的方法,例如intlong 等。 啊,好吧 - 我明白了 - 这是有道理的。今天下午完成了所有内容的更新,我将更改一些名称以使它们符合要求 - 似乎工作得很好,只需要进行一些负载测试并确保一切都很好,并且有很多连接正在运行。非常感谢您的意见。

以上是关于在按值与引用构造数据读取器时配置数据读取器的主要内容,如果未能解决你的问题,请参考以下文章

为啥在按值返回时总是调用复制构造函数

从 sql server 读取数据时检测到自引用循环

在VB中,如何在按下按钮后,读取INI或者TXT文件中的内容并显示在文本框中?

[Javascript] JavaScript赋值时的传值与传址

使用OLEDB读取EXCEL数据时,为何读取不到单元格中的时间值,全是1900\1\0

读取数据时出错,错误消息:CSV 表引用列位置 174,但从位置开始的行:136868 仅包含 94 列