【问题标题】:Enumerable Chaining and Reset可枚举链接和重置
【发布时间】:2012-01-13 17:39:43
【问题描述】:

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

小故事: 我有一个枚举,它从一个文本文件中读取并映射到一个 DTO(请参阅 Map 函数)、一个 Where 枚举器,然后是一个采用枚举的 Import ...这一切都很好,除了当过滤器返回 0 条记录时...在这种情况下,SQL 错误提示 System.ArgumentException: There are no records in the SqlDataRecord enumeration....

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

在我的 Any() 调用之后,我是否需要以某种方式 Reset() 枚举器?为什么在 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();
        }
    }

抱歉,这个例子太长了。感谢阅读...

【问题讨论】:

  • 有没有办法在你分配param.Value=list的时候判断是否有工作要做?我知道这就是您要问的,但也许有一种方法可以通过 param 对象本身来决定是否需要调用 ExecuteReader。

标签: c# linq chaining enumerable


【解决方案1】:

您看到的问题可能不是因为IEnumerable/IEnumerator 接口,而是因为您用于产生价值的底层资源。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    • 2011-11-14
    • 2014-08-22
    相关资源
    最近更新 更多