当前位置:  开发笔记 > 编程语言 > 正文

有人可以揭开yield关键字的神秘面纱吗?

如何解决《有人可以揭开yield关键字的神秘面纱吗?》经验,为你挑选了5个好方法。

我已经看到在Stack Overflow和博客上使用了yield关键字.我不使用LINQ.有人可以解释yield关键字吗?

我知道存在类似的问题.但是没有一个能用简单的语言解释它的用途.



1> Marc Gravell..:

到目前为止,对此(我见过)的最佳解释是Jon Skeet的书 - 那一章是免费的!第6章,C#深入.我无法在这里添加任何未涵盖的内容.

然后买书; 你会成为一个更好的C#程序员.


问:为什么我不在这里写一个更长的答案(从评论中复述); 简单.正如Eric Lippert观察到的那样(这里),yield构造(以及它背后的魔力)是C#编译器中最复杂的代码,并且在一个简短的回复中尝试和描述它至多是天真的.yieldIMO 有很多细微差别,最好引用预先存在的(并且完全合格的)资源.

Eric的博客现在有7个条目(这只是最近的条目)讨论yield.我有一个广阔的埃里克尊重的金额,但他的博客可能更适合作为"更多信息"的人谁舒适的主题(yield在这种情况下),因为它通常描述了很多背景的设计考虑.最好在合理的基础上完成.

(是的,第6章确实下载了;我验证了......)


-1.不要忽视这本书,但这并没有接近回答这个问题.实际上,第6章甚至没有加载.为什么不回答,然后链接到该书以获取更多信息?
非法广告:)
实际上,这一系列文章明确地描述了将非正交性驱动到设计中的迭代器的*怪异角落情况*,而不是关于设计的"主线"情况.
所以我很困惑:我是在这里投票还是在飞碟射击?:P
没关系 - 我们都是当天的最大值;-p

2> Brian Rasmus..:

所述yield关键字被用于与返回的方法IEnumerableIEnumerator它使编译器生成实现必需的管道使用迭代器的类.例如

public IEnumerator SequenceOfOneToThree() {
    yield return 1;
    yield return 2;
    yield return 3;
}

由于编译器将生成一个实现类以上IEnumerator,IEnumerable并且IDisposable(实际上它也将实施的非通用版本IEnumerableIEnumerator).

这使您可以调用该方法SequenceOfOneToThreeforeach这样的循环

foreach(var number in SequenceOfOneToThree) {
    Console.WriteLine(number);
}

迭代器是状态机,因此每次yield调用方法中的位置都会被记录.如果迭代器移动到下一个元素,则该方法在此位置后立即恢复.所以第一次迭代返回1并标记该位置.下一个迭代器在一个之后重新开始,因此返回2,依此类推.

不用说,您可以以任何您喜欢的方式生成序列,因此您不必像我那样对数字进行硬编码.此外,如果你想打破循环,你可以使用yield break.


在12 Stackoverflow,2 msdn和3个网站标签我打开:这是解释*为什么*我会使用yield.这当然是一个棘手的概念,听起来很像过早的优化.

3> apiguy..:

为了揭开神秘面孔,我将避免谈论迭代器,因为它们本身可能是神秘的一部分.

收益率收益和收益率中断语句通常用于提供收集的"延期评估".

这意味着当你得到一个使用yield return的方法的值时,你想要获得的东西的集合不会一起存在(它本质上是空的).当你遍历它们(使用foreach)时,它将在那时执行方法并获取枚举中的下一个元素.

某些属性和方法将导致立即计算整个枚举(例如"计数").

以下是返回集合和返回yield之间差异的快速示例:

string[] names = { "Joe", "Jim", "Sam", "Ed", "Sally" };

public IEnumerable GetYieldEnumerable()
{
    foreach (var name in names)
        yield return name;
}

public IEnumerable GetList()
{
    var list = new List();
    foreach (var name in names)
        list.Add(name);

    return list;
}

// we're going to execute the GetYieldEnumerable() method
// but the foreach statement inside it isn't going to execute
var yieldNames = GetNamesEnumerable();

// now we're going to execute the GetList() method and
// the foreach method will execute
var listNames = GetList();

// now we want to look for a specific name in yieldNames.
// only the first two iterations of the foreach loop in the 
// GetYieldEnumeration() method will need to be called to find it.
if (yieldNames.Contains("Jim")
    Console.WriteLine("Found Jim and only had to loop twice!");

// now we'll look for a specific name in listNames.
// the entire names collection was already iterated over
// so we've already paid the initial cost of looping through that collection.
// now we're going to have to add two more loops to find it in the listNames
// collection.
if (listNames.Contains("Jim"))
    Console.WriteLine("Found Jim and had to loop 7 times! (5 for names and 2 for listNames)");

如果您需要在源数据具有值之前获取对枚举的引用,也可以使用此方法.例如,如果名称集合未完成,则开头:

string[] names = { "Joe", "Jim", "Sam", "Ed", "Sally" };

public IEnumerable GetYieldEnumerable()
{
    foreach (var name in names)
        yield return name;
}

public IEnumerable GetList()
{
    var list = new List();
    foreach (var name in names)
        list.Add(name);

    return list;
}

var yieldNames = GetNamesEnumerable();

var listNames = GetList();

// now we'll change the source data by renaming "Jim" to "Jimbo"
names[1] = "Jimbo";

if (yieldNames.Contains("Jimbo")
    Console.WriteLine("Found Jimbo!");

// Because this enumeration was evaluated completely before we changed "Jim"
// to "Jimbo" it isn't going to be found
if (listNames.Contains("Jimbo"))
    // this can't be true
else
   Console.WriteLine("Couldn't find Jimbo, because he wasn't there when I was evaluated.");


帮助我揭开它的神秘面纱=)

4> dtb..:

yield关键字是编写一个方便的途径IEnumerator.例如:

public static IEnumerator Range(int from, int to)
{
    for (int i = from; i < to; i++)
    {
        yield return i;
    }
}

由C#编译器转换为类似于:

public static IEnumerator Range(int from, int to)
{
    return new RangeEnumerator(from, to);
}

class RangeEnumerator : IEnumerator
{
    private int from, to, current;

    public RangeEnumerator(int from, int to)
    {
        this.from = from;
        this.to = to;
        this.current = from;
    }

    public bool MoveNext()
    {
        this.current++;
        return this.current < this.to;
    }

    public int Current
    {
        get
        {
            return this.current;
        }
    }
}



5> Szymon Rozga..:

请查看MSDN文档和示例.它本质上是一种在C#中创建迭代器的简单方法.

public class List
{
    //using System.Collections;
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}

推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有