代码之家  ›  专栏  ›  技术社区  ›  particle

为什么在包含yield return的函数中重复调用using(){}block?

  •  2
  • particle  · 技术社区  · 13 年前

    我有以下代码。查询需要大约30秒才能执行。我发现上面 using 每次调用块 for each 尝试枚举迭代器。这意味着每次调用 MoveNext 在枚举器中。

    那么为什么懒惰的评估会重新初始化 使用 一次又一次。我知道周围的工作,但我需要了解这个目的。

       private IEnumerable<FriendProfile> GetProfiles() {
            var query = @"
                SELECT VirtualNumber, City, Gender, Nick, Age
                FROM Profiles
                WHERE Not VirtualNumber  In ( SELECT VirtualNumber FROM Messages)
                ORDER BY Id DESC;";
    
            using (var con = GetConnection()) {
                using (var cmd = dbconnection.CreateCommand()) {
                    cmd.CommandText = query;
                    var reader = cmd.ExecuteReader();
                    while (reader.Read()) {
                        var fp = new FriendProfile();
                        fp.VirtualNumber = reader.GetString(0);
                        fp.City = reader.GetString(1);
                        fp.Gender = reader.GetString(2);
                        fp.Nick = reader.GetString(3);
                        fp.Age = reader.GetInt16(4).ToString();
                        yield return fp;
    
                    }
                }
            }
        }
    
    
        foreach(var fp in GetProfiles()){
        .... //foreach item using(){} in GetProfile() is reinitializes. All usings blocks
        }
    
    2 回复  |  直到 13 年前
        1
  •  4
  •   adrianbanks    13 年前

    我不能百分之百确定你指的是哪个使用块,但如果我理解正确,你所说的就不应该发生。这个 yield 将从 GetProfiles() 方法,但是 产量 (即 using 块)将在 while 条件是 false .

    下面是一个简单的例子,可以说明这种行为:

    使用该类显示 使用 执行块:

    public class Disposable : IDisposable
    {
        private readonly string name;
    
        public Disposable(string name)
        {
            this.name = name;
        }
    
        public void Dispose()
        {
            Console.WriteLine("Disposing of {0}", name);
        }
    }
    

    这个代码:

    private IEnumerable<int> Test()
    {
        using (new Disposable("outer"))
        {
            using (new Disposable("inner"))
            {
                for (int i = 0; i < 10; i++)
                {
                    yield return i;
                }
            }
        }
    }
    
    ...
    
    foreach (int i in Test())
    {
        Console.WriteLine("item {0}", i);
    }
    

    输出为:

    item 0
    item 1
    item 2
    item 3
    item 4
    item 5
    item 6
    item 7
    item 8
    item 9
    disposing of inner
    disposing of outer
    

    这表明 使用 块不会退出,直到 for 循环退出。

        2
  •  0
  •   Donnie    13 年前

    是因为路 yield 得到编译。它实际上是对一个类的迭代调用,该类的创建只是为了实现 GetProfiles() 方法。 MoveNext() 在这个过程中,每一步都会调用一次 foreach . This 是一个很好的幕后介绍。