zoukankan      html  css  js  c++  java
  • 从foreach语句枚举元素看数组

    在foreach语句中使用枚举,可以迭代数组或集合中的元素,且无须知道集合中的元素的个数。如图显示了调用foreach方法的客户端和集合之间的关系。数组或集合实现带GetEnumerator()方法的IEnumerable接口。GetEnumerator()方法返回一个实现lEnumerable接口的枚举,接着foreach语句就可以使用IEnumerable接口迭代集合了。

    GetEnumerator()方法用IEnumerable接口定义,foreach语句并不真的需要在集合类中实现这个接口。有一个名为GetEnumerator()的方法它返回实现了IEnumerator接口的对象就足够了。

    先定义一个Person类,这个类有自动实现的属性Firstname和Lastname,以及从Object类重写ToString方法和继承泛型接口IEquatable以比较两个对象是否相等,实现泛型接口IComparer以比较两个对象用来排序。

    public class Person : IEquatable<Person>,IComparable<Person>
        {
            public int Id { get; private set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
    
            public override string ToString()
            {
                return String.Format("{0}, {1} {2}", Id, FirstName, LastName);
            }   
    
            public bool Equals(Person other)
            {
                if (other == null)
                    return base.Equals(other);
    
                return this.FirstName == other.FirstName && this.LastName == other.LastName;
            }
    
            public int CompareTo(Person other)
            {
                if (other == null) throw new ArgumentNullException("other");
    
                int result = this.LastName.CompareTo(other.LastName);
                if (result == 0)
                {
                    result = this.FirstName.CompareTo(other.FirstName);
                }
    
                return result;
            }
    
        }

    创建一个三个元素的person数组,现对数组进行排序在用foreach循环访问数组中的元素并输出

     Person[] persons = {
                    new Person { FirstName = "Simen03", LastName = "Go" },
                    new Person { FirstName = "Simen02", LastName = "Go" },
                    new Person { FirstName = "Simen01", LastName = "Go" }
                };
                Array.Sort(persons);
                foreach (var person in persons)
                    Console.WriteLine(person);

    分析foreach (var person in persons)Console.WriteLine(person);这段代码IL代码

    // loop start (head: IL_009b)
                IL_008a: ldloc.2
                IL_008b: ldloc.3
                IL_008c: ldelem.ref
                IL_008d: stloc.s person
                IL_008f: ldloc.s person
                IL_0091: call void [mscorlib]System.Console::WriteLine(object)
                IL_0096: nop
                IL_0097: ldloc.3
                IL_0098: ldc.i4.1
                IL_0099: add
                IL_009a: stloc.3
    
                IL_009b: ldloc.3
                IL_009c: ldloc.2
                IL_009d: ldlen
                IL_009e: conv.i4
                IL_009f: blt.s IL_008a
            // end loop

    C#的foreach语句不会解析为IL代码中的foreach语句,C#编译器会把foreach语句转换为IEnumerable接口的方法和属性,foreach语句使用IEnumerator接口的方法和属性,迭代数组中的所有元素,为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到数组的下一个元素上,如果有这个元素该方法就返回true否则返回false,这个接口的泛型版本IEnumerator派生自接口IDisposable,因此定义了Dispose()方法来清理枚举器占用的资源,使用foreach语句会解析为下面的代码段

     IEnumerator enumerator = persons.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    var person = enumerator.Current;
                    Console.WriteLine(person);
                }

    为了方便的创建枚举器,C#添加了yield语句,yield return 语句返回集合的一个元素,并移动到下一个元素,yield break 可停止迭代。使用迭代块,编译器会生成一个yield类型,其中包含一个状态机,如下代码段所示。yield 类型实现IEnumerator和IDisposable接口的属性和方法。在下面的例子中,可以把yield类型看作内部类Enumerator.外部类的GetEnumerator()方法实例化并返回一个新的yield类型。在yield类型中,变量state定义了迭代的当前位置,每次调用MoveNext()时,当前位置都会改变,MoveNext()封装了迭代代码,并设置了current变量的值,从而使Current属性根据位置返回一个对象。

     static void Main(string[] args)
            {
                var helloCollection = new HelloCollection();
                foreach (string s in helloCollection)
                {
                    Console.WriteLine(s);
                }
            }
    
            public class HelloCollection
            {
                public IEnumerator<string> GetEnumerator()
                {
                    yield return "Hello";
                    yield return "World";
                }
            }
            public class HelloCollectionOther
            {
                public IEnumerator GetEnumertor()
                {
                    return new Enumerator(0);
                }
                public class Enumerator : IEnumerator<string>, IEnumerator, IDisposable
                {
                    private int state;
                    private string current;
                    public Enumerator(int state)
                    {
                        this.state = state;
                    }
    
                    public string Current => throw new NotImplementedException();
    
                    object IEnumerator.Current
                    {
                        get { return current; }
                    }
    
                    public void Dispose()
                    {
                        throw new NotImplementedException();
                    }
    
                    public bool MoveNext()
                    {
                        switch (state)
                        {
                            case 0:current = "hello";
                                state = 1;
                                return true;
                            case 1:current = "world";
                                state = 2;
                                return true;
                            case 2:
                                break;
                        }
                        return false;
                    }
    
                    public void Reset()
                    {
                        throw new NotImplementedException();
                    }
                }
            }
  • 相关阅读:
    uml 类图
    Java IO流
    Spring 创建Bean的 三种方式
    linux+jmeter+python基础+抓包拦截
    接口测试
    HDU 1159 Common Subsequence(POJ 1458)
    HDU 1160 FatMouse's Speed
    HDU 4540 威威猫系列故事——打地鼠
    HDU 1087 Super Jumping! Jumping! Jumping!
    HDU 1176 免费馅饼
  • 原文地址:https://www.cnblogs.com/simen-tan/p/6816750.html
Copyright © 2011-2022 走看看