C#的IEnumerator /产量结构可能不好? [英] C# IEnumerator/yield structure potentially bad?

查看:288
本文介绍了C#的IEnumerator /产量结构可能不好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:我有一堆我正在从数据库中获取的字符串,我想回报他们。传统上,这将是这样的:

Background: I've got a bunch of strings that I'm getting from a database, and I want to return them. Traditionally, it would be something like this:

public List<string> GetStuff(string connectionString)
{
    List<string> categoryList = new List<string>();
    using (SqlConnection sqlConnection = new SqlConnection(connectionString))
    {
        string commandText = "GetStuff";
        using (SqlCommand sqlCommand = new SqlCommand(commandText, sqlConnection))
        {
            sqlCommand.CommandType = CommandType.StoredProcedure;

            sqlConnection.Open();
            SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
            while (sqlDataReader.Read())
            {
                categoryList.Add(sqlDataReader["myImportantColumn"].ToString());
            }
        }
    }
    return categoryList;
}



但后来我想消费者会希望通过项目迭代不在乎别人约了,我想没有框自己在一个列表,本身,所以如果我回到一个IEnumerable一切都很好/灵活。所以,我想我可以用一个收益回报型设计来处理这个......是这样的:

But then I figure the consumer is going to want to iterate through the items and doesn't care about much else, and I'd like to not box myself in to a List, per se, so if I return an IEnumerable everything is good/flexible. So I was thinking I could use a "yield return" type design to handle this...something like this:

public IEnumerable<string> GetStuff(string connectionString)
{
    using (SqlConnection sqlConnection = new SqlConnection(connectionString))
    {
        string commandText = "GetStuff";
        using (SqlCommand sqlCommand = new SqlCommand(commandText, sqlConnection))
        {
            sqlCommand.CommandType = CommandType.StoredProcedure;

            sqlConnection.Open();
            SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
            while (sqlDataReader.Read())
            {
                yield return sqlDataReader["myImportantColumn"].ToString();
            }
        }
    }
}



不过,现在我正在读一本详细了解产量位(这样的网站... MSDN似乎并没有提到这一点),这显然是一个懒惰的评估,即保持填充器的状态各地,在别人的预期要求下一个值,然后只直到它返回的下一个值运行它。

But now that I'm reading a bit more about yield (on sites like this...msdn didn't seem to mention this), it's apparently a lazy evaluator, that keeps the state of the populator around, in anticipation of someone asking for the next value, and then only running it until it returns the next value.

这似乎在大多数情况下细,但有一个DB调用,这听起来有点冒险。作为一个有些人为的例子,如果有人要求从我从DB调用填充一个IEnumerable,得到通过它的一半,然后卡在循环......据我可以看到我的DB连接是怎么回事要保持开放,直到永远。

This seems fine in most cases, but with a DB call, this sounds a bit dicey. As a somewhat contrived example, if someone asks for an IEnumerable from that I'm populating from a DB call, gets through half of it, and then gets stuck in a loop...as far as I can see my DB connection is going to stay open forever.

听起来像在某些情况下,自寻烦恼,如果迭代器未完成......我失去的东西吗?

Sounds like asking for trouble in some cases if the iterator doesn't finish...am I missing something?

推荐答案

这是一个平衡的行为:你要的所有数据强制到内存立刻让你可以释放连接,或者你想从流中获益的数据,占用了所有的时间连接的成本是多少?

It's a balancing act: do you want to force all the data into memory immediately so you can free up the connection, or do you want to benefit from streaming the data, at the cost of tying up the connection for all that time?

我的方式看,这个决定应该有可能达到调用者,谁知道更多关于他们想要做什么。如果你写使用迭代器块中的代码,调用者可以的非常的容易打开,流式的形式进入全缓冲方式:

The way I look at it, that decision should potentially be up to the caller, who knows more about what they want to do. If you write the code using an iterator block, the caller can very easily turned that streaming form into a fully-buffered form:

List<string> stuff = new List<string>(GetStuff(connectionString));

如果,在另一方面,你也缓冲自己,有没有办法调用者可以回去以流模式。

If, on the other hand, you do the buffering yourself, there's no way the caller can go back to a streaming model.

所以,我可能会使用流模型,说的明确的它做什么的文档中,并告知呼叫者适当决定。你甚至可能要提供一个辅助的方法基本上调用流版本,并将其转换成一个列表。

So I'd probably use the streaming model and say explicitly in the documentation what it does, and advise the caller to decide appropriately. You might even want to provide a helper method to basically call the streamed version and convert it into a list.

当然,如果你不信任你的来电,使适当的决定,你有充分的理由相信,他们永远不会真的要流的数据(例如,它永远不会返回反正很多),然后去列表的方法。无论哪种方式,将其记录下来 - 它很可能会影响返回值是用来

Of course, if you don't trust your callers to make the appropriate decision, and you have good reason to believe that they'll never really want to stream the data (e.g. it's never going to return much anyway) then go for the list approach. Either way, document it - it could very well affect how the return value is used.

有关处理大量数据的另一种选择是使用批次,当然 - 这是打算把原来的问题有点远,但它是一个不同的方法在流通常是有吸引力的情况来考虑。

Another option for dealing with large amounts of data is to use batches, of course - that's thinking somewhat away from the original question, but it's a different approach to consider in the situation where streaming would normally be attractive.

这篇关于C#的IEnumerator /产量结构可能不好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆