0

我有一个执行 SQL 语句的方法,它返回我的类的一个实例,ResultSet其中包含返回的行和列。我只想在调用者实际迭代结果时逐行读取数据。

public class ResultSet {
    public IEnumerable<Row> Rows {
        get;
        private set;
    }
    public ResultSet(IEnumerable<Row> rows, IEnumerable<Column> columns) {
        Rows = rows;
        // columns and other code omitted
    }
}

为此,我尝试将 IEnumerable 传递给我的类的构造函数,但问题是 DbDataReader 实例在您尝试迭代实例的Rows属性时已经被释放ResultSet

    public ResultSet Execute(string sql) {
        using (var command = Connection.CreateCommand()) {
            command.CommandText = sql;

            var reader = command.ExecuteReader();
            try {
                IEnumerable<Row> MyFunc()
                {
                    while (reader.Read())
                        yield return new Row(reader);
                }
                var columns = GetColums(...);
                return new ResultSet(MyFunc(), columns);
            } finally {
                reader.Dispose();
            }
        }
    }

我知道我可以将 DbDataReader 实例传递给我的类,而不是在Execute方法中处理它,但是我必须ResultSet一次性使用,如果可能的话,我想避免这种情况。我不确定我正在尝试做什么?

在执行之前查看了 using() { } 块 Disposes 内的 yield return 语句,但它并不完全相同,因为它不涉及一次性资源。

4

1 回答 1

0

为了说明我的评论:

public class Row
{
    public Row(IDataReader reader)
    { }
};

public class RowEnumerator : IEnumerator<Row>
{
    public RowEnumerator(IDbConnection connection, string SQL)
    {
        _command = connection.CreateCommand();
        _command.CommandText = SQL;

        _reader = _command.ExecuteReader();
    }
    private readonly IDbCommand _command;
    private readonly IDataReader _reader;

    public Row Current => new Row(_reader);

    object IEnumerator.Current => Current;

    public bool MoveNext() => _reader.Read();

    public void Reset() => throw new NotImplementedException();

    public void Dispose()
    {
        _reader.Dispose();
        _command.Dispose();
    }
}

public class RowEnumerable : IEnumerable<Row>
{
    public RowEnumerable(IDbConnection connection, string SQL)
    {
        _connection = connection;
        _SQL = SQL;
    }
    private readonly IDbConnection _connection;
    private readonly string _SQL;

    public IEnumerator<Row> GetEnumerator() => new RowEnumerator(_connection, _SQL);

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

查询在RowEnumerator创建 a 时执行,即何时RowEnumerable.GetEnumerator调用。

如果在foreach循环中使用可枚举,枚举数,因此命令和阅读器,将被自动处理。否则,您必须手动处理它。

于 2018-07-23T14:47:40.007 回答