从 IDisposable 实例返回带有 yield 的 IEnumerable<T>

Returning IEnumerable<T> with yield from IDisposable instance

我发现了一个有趣的事情。 C#,.NET 4.0。 我有一个 class 代表 IDisposable 接口。在提到的 class 中,我有一个函数,returns with IEnumerable with yield return。 在调用时,控件会跳过该函数。不要介入。 示例:

class Program
{
    static void Main(string[] args)
    {
        using (DispClass d = new DispClass())
        {
            d.Get2();
            d.Get1();
        }
    }

}

public class DispClass: IDisposable
{
    public DispClass()
    {
        Console.WriteLine("Constructor");
    }
    public void Dispose()
    {
        Console.WriteLine("Dispose");
    }
    public int Get1()
    {
        Console.WriteLine("Getting one");
        return 1;
    }
    public IEnumerable<int> Get2()
    {
        Console.WriteLine("Getting 1");
        yield return 1;
        Console.WriteLine("Getting 2");
        yield return 2;
    }

}

输出: "Constructor" "Getting one" "Dispose"

"Getting 1"、"Getting 2"在哪里? 如果没有 yield return 和 returning 本地列表,我可以看到这些...

请说明!

这是设计使然的预期行为。当您使用 yield 时,实际发生的是 Get2 方法返回一个由编译器自动实现的类型的实例。该类型实现了 IEnumerable<T> 接口。在枚举可枚举对象之前,迭代器方法中的代码实际上不会被调用。由于您没有枚举 Get2 调用的结果,因此永远不会调用您的代码。要强制执行它,请使用 ToArray()ToList():

 d.Get2().ToList();

方法 Get2() 中的代码只有在您迭代由该方法编辑的 IEnumerable return 时才会执行。 由于本例中的 IEnumerable 包含两个元素,因此它将输入此代码两次 - 在第一次迭代期间,它将执行第一个两行并在“yield return 1; 处退出函数; 在下一次迭代期间,它将进入函数并在 "Console.WriteLine("Getting 2");" 行开始执行。并从那里继续。

因此,如果您不遍历这两个项目,即在获得值 1 后,您不移动到 IEnumerable 中的下一个项目,那么该函数将不会再次进入。 尝试将您的程序更改为以下代码以获得更好的理解。

    static void Main(string[] args)
    {
        using (DispClass d = new DispClass())
        {
            var lst = d.Get2();
            //d.Get1();

            foreach (var a in lst)
            {
                break;
            }
        }
        Console.ReadKey();
    }