原文:[原译]实现IEnumerable接口&理解yield关键字 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢! 本文讨论题目的内容。
原文: [原译]实现IEnumerable接口&理解yield关键字

著作权声明:本文由 http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

本文讨论题目的内容。然后讨论IEnumerable接口如何使得foreach语句可以使用。之后会展示如果实现自定义的集合类,该集合类实现了IEnumerable接口。Yield关键字和遍历集合后面也讨论。

一使用集合。就发现遍历集合就跟着来了。遍历集合最好的方式是实现迭代器模式- Understanding and Implementing the Iterator Pattern in C# and C++ (这篇文章我过几天翻译一下) ,C#提供foreach来以一种优雅的方式遍历

只要集合实现了IEnumerable 接口就可以用foreach来遍历。

首先先看一下内置的集合类如何使用foreach来遍历的。ArrayList实现了IEnumerable 接口。我们看一下

// 看一下实现了IEnumerable 接口的集合如何遍历
ArrayList list = new ArrayList();
list.Add("1");
list.Add(2);
list.Add("3");
list.Add('4');
foreach (object s in list)
    Console.WriteLine(s);

遍历泛型集合类

Arraylist 是一个通用集合类,遍历泛型集合类也可以。因为这些泛型集合类实现了IEnumerable<T>接口,看一下吧。

// 遍历实现了IEnumerable<T>接口的泛型类
List<string> listOfStrings = new List<string>();
listOfStrings.Add("one");
listOfStrings.Add("two");
listOfStrings.Add("three");
listOfStrings.Add("four");
foreach (string s in listOfStrings)
    Console.WriteLine(s);

发现了吧。我们自定义的集合类或是泛型集合类应该实现IEnumerable和IEnumerable<T>接口。这样就可以遍历了。

理解yield关键字

在写个实现接口的例子之前,先理解一下yield关键字,yield会记录集合位置。当从一个函数返回一个值的时候,yield可以用。

如下的普通的方法。不论调用多少次,都只会返回一个return

static int SimpleReturn()
    return 1;
    return 2;
    return 3;
static void Main(string[] args)
    // 看看
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());
    Console.WriteLine(SimpleReturn());

原因就是普通的return语句不保留函数的返回状态。每一次都是新的调用。然后返回第一个值。

但是使用下面的语句替换后就不一样。当函数第二次调用的时候。会从上次返回的地方继续调用

static IEnumerable<int> YieldReturn()
    yield return 1;
    yield return 2;
    yield return 3;
static void Main(string[] args)
    // 看看yield return的效果
    foreach (int i in YieldReturn())
        Console.WriteLine(i);

显然返回1,2,3,唯一要注意的就是函数需要返回IEnumerable。,然后通过foreach调用。

在自定义的集合类里实现Ienumerable接口

现在如果我们在我们的自定义集合里定义一个方法。来迭代所有元素。然后通过使用yield返回。我们就可以成功了。

好。我们定义MyArrayList 类,实现IEnumerable 接口,该接口就会强制我们实现GetEnumerator 函数。这里我们就要使用yield了。

class MyArrayList : IEnumerable
    object[] m_Items = null;
    int freeIndex = 0;
    public MyArrayList()
        // 对了方便我直接用数组了,其实应该用链表
       m_Items = new object[100];
    public void Add(object item)
        // 考虑添加元素的时候
        m_Items[freeIndex] = item;
        freeIndex++;
    // IEnumerable 函数
    public IEnumerator GetEnumerator()
       foreach (object o in m_Items)
           // 检查是否到了末尾。数组的话。。。没写好
            if(o == null)
                break;
            // 返回当前元素。然后前进一步
            yield return o;
     #region IEnumerable Members
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        // 此处调用泛型版本
        return this.GetEnumerator();
    #endregion

之后就可以使用foreach了。

static void Main(string[] args)
    // 使用示例
    MyList<string> myListOfStrings = new MyList<string>();
    myListOfStrings.Add("one");
    myListOfStrings.Add("two");
    myListOfStrings.Add("three");
    myListOfStrings.Add("four");
    foreach (string s in myListOfStrings)
        Console.WriteLine(s);

 源代码下载

EnumerableDemo.7z

原文地址: A-Beginners-Tutorial-on-Implementing-IEnumerable-I

著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

Scala yield关键字 Scala中的yield关键字与for循环一起使用。它在每个for循环迭代中存储一个变量。存储的变量组合在一起,以创建与for循环在同一时间运行的新结构。例如,在映射上使用yield会为列表,数组向量等提供类似的映射结构。 yield的语法是
🔖 Lambda Expression 是 Java8 开始才有的语法 🔖 函数式接口(Functional Interface):只包含1个抽象方法的接口(可以包含多个默认方法和静态方法) 📕 可以在接口上加上@FunctionalInterface注解,表示它是一个函数式接口 🔖 当匿名类实现的是函数式接口的时候,可以使用 Lambda 表达式简化代码的书写(但是匿名类和 Lambda 在作用域上还是有点区别的)
C#(二十二)之抽象方法 密封方法 base new 关键字
本篇内容记录了普通方法的隐藏(new)、base关键字、抽象类和抽象方法(abstract)、密封类和蜜蜂方法(sealed)的简单用法。
【Groovy】闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )
【Groovy】闭包 Closure ( 闭包调用 与 call 方法关联 | 接口中定义 call() 方法 | 类中定义 call() 方法 | 代码示例 )
接口可以包含常量, 且不需要publish static final修饰, 接口的域会自动添加该修饰符. Java建议不要写多余的代码,因此省略修饰符更简洁. 全部都是常量的接口背离了接口的初衷,不建议使用 Java SE8 中, 允许接口增加静态方法,但这也有悖接口的初衷 接口的默认方法实...
synchronized关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用synchronized(对象) { … }定义同步代码块,或者在声明方法时将synchronized作为方法的修饰符。