【问题标题】:Returning IEnumerable<T> with yield from IDisposable instance从 IDisposable 实例返回带有产量的 IEnumerable<T>
【发布时间】:2017-02-14 04:33:13
【问题描述】:

我发现了一件有趣的事情。 c#,.NET 4.0。 我有一个代表 IDisposable 接口的类。在提到的类中,我有一个函数,它返回 IEnumerable 和 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;
    }

}

输出: “建设者” “得到一个” “处置”

“得到 1”、“得到 2”在哪里? 如果没有返回本地列表的收益返回,我可以看到这些......

请解释一下!

【问题讨论】:

  • 您需要使用从对Get2 的调用返回的IEnumerable,也许使用foreach 语句?
  • yield return 使该方法(神奇地)返回一个包含方法中代码的枚举器对象。它只是坐在那里等待被枚举,但你永远不会枚举它。你觉得这让人感觉如何?试试d.Get2().ToList();
  • P.S.这就是yield return 的全部目的:有人调用您的方法,但在实际需要之前,没有任何代码实际执行。例如,这允许调用者仅遍历方法中冗长的 foreach 循环的部分,从而节省时间和资源。这是一项功能,而不是错误。
  • 你可能想阅读stackoverflow.com/questions/39476/…(以及关于yield return的类似帖子)
  • 另外,请阅读 minimal reproducible example 发布示例指南 - 如果您仔细遵循它,您的帖子不会谈论完全不相关的 IDisposable 实施...考虑 edit 您的帖子以删除不相关的 IDisposable 引用以及大部分代码或阐明为什么您认为它是帖子的重要部分。

标签: c# idisposable yield


【解决方案1】:

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

 d.Get2().ToList();

【讨论】:

    【解决方案2】:

    Get2() 方法中的代码仅在您遍历该方法返回的 IEnumerable 时才会执行。 由于本例中的 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();
        }
    

    【讨论】:

      猜你喜欢
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      相关资源
      最近更新 更多