C# 可枚举链接和重置

C# 可枚举链接和重置,c#,linq,chaining,enumerable,C#,Linq,Chaining,Enumerable,我正在尝试将一个文件导入数据库,并在此过程中学习一种更有效的方法。建议的链式枚举产生较低的内存使用率和良好的性能。 这是我第一次链接几个枚举,我不太确定如何正确处理重置 短篇故事: 我有一个枚举,它从文本文件读取数据并映射到DTO(请参阅映射函数),一个Where枚举器,然后是一个接受枚举的导入。。。这一切都很完美,只是当过滤器返回0条记录时。。。在这种情况下,SQL错误会显示System.ArgumentException:SqlDataRecord枚举中没有记录。 因此,我在if(!list

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

短篇故事: 我有一个枚举,它从文本文件读取数据并映射到DTO(请参阅映射函数),一个Where枚举器,然后是一个接受枚举的导入。。。这一切都很完美,只是当过滤器返回0条记录时。。。在这种情况下,SQL错误会显示
System.ArgumentException:SqlDataRecord枚举中没有记录。

因此,我在if(!list.Any())返回时放置了一个
在我的导入方法的顶部,它似乎不出错。除此之外,它将始终跳过文本文件中直到(包括)第一个有效行的所有行

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

代码:

公共IEnumerable映射(TextReader sr)
{
while(null!=(line=sr.ReadLine())
{
var dto=新的dto();
var row=line.Split('\t');
//…映射逻辑在这里。。。
收益率(T)obj;
}
}
//过滤器,在别处调用
列表。其中(x=>Valid(x))。选择(x=>LoadSqlRecord(x))
公共无效导入(IEnumerable列表)
{
使用(var conn=new SqlConnection(…)
{
如果(连接状态!=连接状态打开)
conn.Open();
var cmd=conn.CreateCommand();
cmd.CommandText=“导入数据”;
cmd.CommandType=System.Data.CommandType.StoredProcess;
var parm=新的SqlParameter();
cmd.Parameters.Add(parm);
parm.ParameterName=“数据”
parm.TypeName=“udt\u DTO”;
parm.SqlDbType=SqlDbType.Structured;
参数值=列表;
cmd.ExecuteNonQuery();
康涅狄格州关闭();
}
}

很抱歉给你举了这么长的例子。感谢阅读…

您看到的问题可能不是因为
IEnumerable
/
IEnumerator
接口,而是因为您正在使用底层资源来生成值

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


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

您看到的问题可能不是因为
IEnumerable
/
IEnumerator
接口,而是因为您正在使用底层资源生成值

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


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

是否有方法在分配param.Value=list时确定是否有任何工作要做?我知道这就是你要问的,但也许有一种方法可以通过param对象本身来决定是否需要调用ExecuteReader。在分配param.Value=list时,有没有一种方法可以确定是否有任何工作要做?我知道这就是你要问的,但也许有一种方法可以通过param对象本身来决定是否需要调用ExecuteReader。
    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();
        }
    }