关于.net 2.0:使用yield遍历数据读取器可能不会关闭连接吗?

关于.net 2.0:使用yield遍历数据读取器可能不会关闭连接吗?

Using yield to iterate over a datareader might not close the connection?

这是一个示例代码,用于使用谷歌搜索时在几个地方找到的yield关键字从数据库检索数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public IEnumerable<object> ExecuteSelect(string commandText)
{
    using (IDbConnection connection = CreateConnection())
    {
        using (IDbCommand cmd = CreateCommand(commandText, connection))
        {
             connection.Open();
             using (IDbDataReader reader = cmd.ExecuteReader())
             {
                while(reader.Read())
                {
                    yield return reader["SomeField"];
                }
             }
             connection.Close();
        }
    }
}

我是否正确认为在此示例代码中,如果不对整个数据读取器进行迭代,则连接将不会关闭?

如果我正确理解yield,这是一个不会关闭连接的示例。

1
2
3
4
foreach(object obj in ExecuteSelect(commandText))
{
  break;
}

对于可能不会造成灾难性的数据库连接,我想GC最终会清理它,但是如果不是连接而是更关键的资源怎么办?


编译器综合的迭代器实现IDisposable,当退出foreach循环时,foreach会调用该迭代器。

迭代器的Dispose()方法将在提早退出时清除using语句。

只要您在foreach循环,using()块中使用迭代器,或以其他方式调用Dispose()方法,就会进行迭代器的清理。


从我尝试过的简单测试来看,aku是正确的,只要foreach块退出,就立即调用配置。

@David:但是在调用之间保持调用堆栈,因此连接不会关闭,因为在下一个调用中,我们将在yield之后的下一条指令返回while语句,这是while块。

我的理解是,当处置迭代器时,连接也将随之处置。我也认为不需要Connection.Close,因为由于using子句,它将在处理对象时照顾到它。

这是我尝试测试行为的简单程序...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Program
{
    static void Main(string[] args)
    {
        foreach (int v in getValues())
        {
            Console.WriteLine(v);
        }
        Console.ReadKey();

        foreach (int v in getValues())
        {
            Console.WriteLine(v);
            break;
        }
        Console.ReadKey();
    }

    public static IEnumerable<int> getValues()
    {
        using (TestDisposable t = new TestDisposable())
        {
            for(int i = 0; i<10; i++)
                yield return t.GetValue();
        }
    }
}

public class TestDisposable : IDisposable
{
    private int value;

    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }

    public int GetValue()
    {
        value += 1;
        return value;
    }
}

由于您在"使用"块中使用连接,连接将自动关闭。


从此技术说明来看,您的代码将无法按预期运行,但会在第二项上中止,因为返回第一项时连接已关闭。

@Joel Gauvreau:是的,我应该继续读下去。本系列的第3部分解释了编译器为final块添加了特殊处理,以便仅在真实端触发。


推荐阅读

    linux遍历文件命令?

    linux遍历文件命令?,系统,数据,工具,文件,平台,信息,百度,位置,时间,适当,lin

    linux命令连接ip?

    linux命令连接ip?,地址,系统,网络,工作,信息,命令,密码,名称,设备,服务,linux

    linux命令连接网址?

    linux命令连接网址?,网址,系统,地址,服务,传播,数据,命令,名字,环境,网站,如

    linux存储数据命令?

    linux存储数据命令?,系统,管理,数据,设备,情况,地址,工作,命令,服务,平台,Lin

    linux数据库查找命令?

    linux数据库查找命令?,位置,名称,状态,服务,软件,信息,系统,命令,名字,密码,

    linux数据库同步命令?

    linux数据库同步命令?,信息,系统,汽车,车辆,服务,工作,通信,一致,分析,数据,D

    linux连接多条命令?

    linux连接多条命令?,工具,情况,命令,分行,服务,地址,连续,终端,窗口,主机,lin

    linux命令搜索大全?

    linux命令搜索大全?,地址,工作,系统,命令,管理,目录,标准,基础,工具,网络,lin

    linux有线网连接命令?

    linux有线网连接命令?,系统,网络,软件,电脑,密码,地址,信息,虚拟机,终端,命

    linux编译连接命令?

    linux编译连接命令?,系统,代码,环境,工具,文件,资料,电脑,百度,终端,命令,在l

    linux建立数据库命令?

    linux建立数据库命令?,软件,系统,工作,数据,密码,工具,数据库,一致,网络,服

    linux命令进数据库?

    linux命令进数据库?,地址,系统,名字,服务,密码,命令,读法,数据库,操作系统,

    linux上的软连接命令?

    linux上的软连接命令?,系统,设备,位置,链接,文件,数据,交通,地方,信息,地址,L

    linux搜索过去命令?

    linux搜索过去命令?,系统,信息,命令,名称,工作,预期,数字,地址,标准,服务,Lin

    linux清空表数据命令?

    linux清空表数据命令?,系统,数据,软件,名称,不了,命令,文件,电脑,地址,位置,L

    linux拷贝数据命令?

    linux拷贝数据命令?,系统,地址,文件,数据,命令,目录,服务,基本知识,项目,密

    linux命令搜索命令?

    linux命令搜索命令?,系统,位置,地址,标准,管理,信息,命令,名称,工作,文件,Lin

    mac命令连接linux?

    mac命令连接linux?,系统,软件,电脑,密码,公司,网络,地址,通用,服务,发展,macb

    linux日志搜索命令?

    linux日志搜索命令?,信息,系统,对比,工具,一致,日志,文件,命令,实时,网络,lin

    linux命令字符搜索?

    linux命令字符搜索?,系统,工具,命令,灵活,信息,工作,字符串,文本,文件,模式,l