zoukankan      html  css  js  c++  java
  • 造假造上瘾——仿造yield关键字(二)

            本篇我们讨论for和foreach配合yield的情况。首先看如下代码以及生成的隐藏类。

            public static IEnumerable Power(int baseNumber, int highExponent)
            {
                int result = 1;
    
                for (int counter = 1; counter <= highExponent; counter++)
                {
                    result = result * baseNumber;
                    yield return result;
                }
            }

            这是一个算baseNumber的highExponet次幂的方法,在for循环里每计算一次就通过yield返回。在Reflector里,该方法是长成这样的:

            再看一下生成的<Power>d_0这个类,因为本文的目的是仿造yield关键字,所以这里仅贴出类定义,具体实现有兴趣各位自己看一下哈哈。

            那么紧接着我们就来仿造一个yield类来代替这个生成的类,去掉不必要的接口和多余的字段,干脆连状态机也拿掉,一切从简之后代码如下:

        class FakeYieldPower : IEnumerable, IEnumerator
        {
            private object current;
            private int counter = 1;
            private int result = 1;
            public int baseNumber;
            public int highExponent;
    
            public bool MoveNext()
            {
                if (this.counter > this.highExponent)
                {
                    return false;
                }
                else
                {
                    this.result *= this.baseNumber;
                    this.current = this.result;
                    this.counter++;
                    return true;
                }
            }
    
            public IEnumerator GetEnumerator()
            {
                return new FakeYieldPower { baseNumber = this.baseNumber, highExponent = this.highExponent };
            }
    
            public void Reset()
            {
                throw new NotSupportedException();
            }
    
            public object Current
            {
                get
                {
                    return this.current;
                }
            }
        }

            也许有人会问,为什么yield返回值一定要同时实现IEnumerable和IEnumerator2个接口。通过IEnumerable接口中的GetEnumerator方法,可以得到一个单纯的实现IEnumerator接口的类,这样划分更清晰,类的职责更明确。其实我也不是很肯定啊,我个人的理解是可以少生成一个隐藏类,同时可以方便地把IEnumerable和IEnumerator转来转去……哎呀,不要扔鸡蛋啊……各位我们先看使用效果……

            public static void Process()
            {
                // Output: 2 4 8 16 32 64 128 256
                foreach (int number in Power2(2, 8))
                {
                    Console.Write(number.ToString() + " ");
                }
            }
    
            public static IEnumerable Power2(int baseNumber, int highExponent)
            {
                return new FakeYieldPower { baseNumber= baseNumber, highExponent= highExponent };
            }

            经本人鉴定是好使的,最显著的变化是我把state状态给删了,这说明yield不是一定要switch case配合state弄成个状态机,里面再插2个goto语句。至于MS为什么这么做,我想是因为该类是自动生成,状态机是一个好选择。按照一定的算法能生成通用的代码。

            for循环看完之后接下来我们看一下foreach,这个其实有点蛋疼了,因为能使用foreach的对象,本身就实现了IEnumerable,再把他用yield转成IEnumerable和IEnumerator的混合体返回还是蛮奇怪的。比如:

            public IEnumerable<Person> GetPerson()
            {
                List<Person> personList = this.GetPersonList();
                foreach (var p in personList)
                {
                    yield return p;
                }
            }

            生成的代码绝对会让你产生蛋蛋的忧伤,还是伪造yield好了:

            public IEnumerable<Person> GetPersonEnumerable()
            {
                return this.GetPersonList();
            }
    
            public IEnumerator<Person> GetPersonEnumerator()
            {
                return this.GetPersonList().GetEnumerator();
            }

            别打……别打了,真的没有的可以伪造的余地啊,本来就已经都写好了啊T_T

            还是来测试一下使用效果,必须效果杠杠滴,就跟CCAV一样,都彩排好了,不OK我不放出来:

                foreach (var p in person.GetPersonEnumerable())
                {
                    Console.WriteLine(p.Name);
                }
    
                var iterator = person.GetPersonEnumerator();
                while (iterator.MoveNext())
                {
                    Console.WriteLine(iterator.Current.Name);
                }

            至此我们对yield的学习告一段落,话说yield确实省了我们不少行代码,提高了生产了。当然负面的作用就是让初学者云里雾里不明所以。

            代码下载

            

  • 相关阅读:
    MarkDown的快速入门
    openCV打开摄像头,用openGL实现纹理贴图和视频预览
    tensorflow中的dropout是怎么实现的?
    BEEPS-仿美图秀秀磨皮算法,让美女的皮肤更光滑
    鄙人提出的PBDRLSE分割算法(绝对原创)
    怀旧风格照片特效
    铅笔特效算法
    背光图像的增强
    关于push和concat的性能问题
    小程序日历签到
  • 原文地址:https://www.cnblogs.com/manupstairs/p/2817239.html
Copyright © 2011-2022 走看看