可枚举的链接和重置

时间:2011-12-06 02:06:19

标签: c# linq chaining enumerable

我正在尝试将文件导入数据库,并在此过程中学习更有效的方法。 This article建议链接枚举产生低内存使用率和良好性能。 这是我第一次链接几个枚举,我不太确定如何正确处理重置......

短篇小说: 我有一个枚举,它从文本文件中读取并映射到DTO(参见Map函数),Where枚举器,然后是一个带枚举的Import ...除了当过滤器返回0记录时,它都完美地工作...在这种情况下,SQL错误说System.ArgumentException: There are no records in the SqlDataRecord enumeration. ...

所以我在我的Import方法的顶部放了一个if(!list.Any()) return;,它似乎没有错误。除了它将始终跳过文本文件中第一个有效行的所有行(包括)...

在Any()调用之后,我是否需要以某种方式重置()枚举器?当在Linq和其他Enumerable实现中使用相同的结构时,为什么这不是必需的?

代码:

    public IEnumerable<DTO> Map(TextReader sr)
    {
        while (null != (line = sr.ReadLine()))
        {
            var dto = new DTO();
            var row = line.Split('\t');
            // ... mapping logic goes here ...

            yield return (T)obj;
        }
    }

    //Filter, called elsewhere 
    list.Where(x => Valid(x)).Select(x => LoadSqlRecord(x))

    public void Import(IEnumerable<SqlDataRecord> list)
    {
        using (var conn = new SqlConnection(...))
        {
            if (conn.State != ConnectionState.Open)
                conn.Open();

            var cmd = conn.CreateCommand();
            cmd.CommandText = "Import_Data";
            cmd.CommandType = System.Data.CommandType.StoredProcedure;

            var parm = new SqlParameter();
            cmd.Parameters.Add(parm);
            parm.ParameterName = "Data"
            parm.TypeName = "udt_DTO";
            parm.SqlDbType = SqlDbType.Structured;
            parm.Value = list;

            cmd.ExecuteNonQuery();
            conn.Close();
        }
    }

很抱歉这个长长的例子。谢谢你的阅读...

1 个答案:

答案 0 :(得分:1)

您看到的问题可能不是因为IEnumerable / IEnumerator接口,而是因为您使用的基础资源来生成值。

对于大多数枚举,添加list.Any()不会导致将来list的枚举跳过项,因为每次调用list.GetEnumerator都会返回独立的对象。您可能有其他原因不想创建多个枚举器,例如通过LINQ to SQL多次调用数据库,但每个枚举器都会获取所有项目。

但是,在这种情况下,由于底层资源,使多个枚举器无法工作。根据您发布的代码,我假设传递给Import的参数基于您发布的Map方法的调用。每次通过Map返回的可枚举时,您将在方法的顶部“开始”,但TextReader及其当前位置在所有枚举器之间共享。即使您尝试在IEnumerators上调用Reset,也不会重置TextReader。要解决您的问题,您需要缓冲可枚举(例如ToList)或找到重置TextReader的方法。