KiddLee

态度决定一切!我博客,留住生活中的精彩
数据加载中……
小议foreach

       今天给一个同事讲一个程序,应该是一个比较基础的程序,但是把我给难住了(哎,才发现自己的基础也滥的可以了),程序大概是这样的:

    public class MyStringArray : IEnumerable

    {

        public IEnumerator GetEnumerator()

        {

            return (IEnumerator)new MyStringArrayEnumerator(this);

        }

        public MyStringArray(params string[] Strings)

        {

            strings = new string[10];

            foreach(string s in Strings)

            {

                strings[ind++] = s;

            }

        }

        public void Add(string addedstr)

        {

            strings[ind++] = addedstr;

        }

        public string this[int strind]

        {

            get

            {

                return strings[strind];

            }

            set

            {

                strings[strind] = value;

            }

        }

        public string[] strings;

        public int ind=0;

    }

 

    public class MyStringArrayEnumerator:IEnumerator

    {

        public MyStringArrayEnumerator(MyStringArray strarr)

        {

            this.strarr = strarr;

            index = -1;

        }

        public bool MoveNext()

        {

            index++;

            if(index>=strarr.strings.Length)

                return false;

            else

                return true;

        }

        public void Reset()

        {

            index = -1;

        }

        public object Current

        {

            get

            {

                return(strarr[index]);

            }

        }

        MyStringArray strarr;

        int index;

    }

 

    class Class1

    {

        [STAThread]

        static void Main(string[] args)

        {      

            MyStringArray strarr = new MyStringArray("This","is","a","test.");

            strarr.Add("You");

            strarr.Add("are");

            strarr.Add("Welcome");

            strarr[2] = "another";

            foreach(string s in strarr)

            {

                Console.WriteLine("{0}",s);

            }

        }

    }

       当断点跟踪到foreach的时候再往下跟踪,就不太明白了。首先程序读取strarr对象的时候进入了MyStringArray. GetEnumerator方法,然后获取到一个MyStringArrayEnumerator对象,然后,光标又到了foreach关键字上,接着进入了MyStringArrayEnumerator. MoveNext方法中,从这个方法跳出后,跟踪点有移到了string s in上,然后又跟踪到了MyStringArrayEnumerator. Current属性中,然后又回到string s in能得莫名其妙的。

当时,我说了一句者可能是IEnumerable接口的内部机制(我这个概念错误应该是很严重的,接口中不可能调用这些方法)。那是为什么跟踪的结果会这样。我试图改造循环显示的部分,用for循环,但是发现strarr对象没有类似CountLength的属性。

查看MSDN上对foreach使用的解释:

 foreach (type identifier in expression) statement

其中:

type

identifier 的类型。

identifier

表示集合元素的迭代变量。如果迭代变量为值类型,则无法修改的只读变量也是有效的。

expression

对象集合或数组表达式。集合元素的类型必须可以转换为 identifier 类型。请不要使用计算为 null 的表达式。

而应计算为实现 IEnumerable 的类型或声明 GetEnumerator 方法的类型。在后一种情况中,GetEnumerator 应该要么返回实现 IEnumerator 的类型,要么声明 IEnumerator 中定义的所有方法。

statement

要执行的嵌入语句。

    实际上,应该是foreach调用GetEnumerator方法,这个方法要返回一个IEnumerator对象。foreach应该是利用这个IEnumerator对象中方法实现的简单的便利。后来,试验了一下MyStringArray类不继承IEnumerable接口,但是实现了GetEnumerator方法,结果是一样的

posted on 2006-07-27 17:53 KiddLee 阅读(1949) 评论(7)  编辑 收藏 所属分类: 每日所见记录

评论

#1楼  2006-07-28 15:11 叶漂      

首先我不明白楼主"不太明白"什么.
其次楼主说"但是发现strarr对象没有类似Count或Length的属性",这么一个简单的属性,楼主完全可以自己加一个.
再有,你在MyStringArray的构造函数中
strings = new string[10];这不就太没有灵活性了吗,难道你的数组的容量就是10.
    回复  引用  查看    

#2楼 [楼主] 2006-07-29 00:30 kid_li      

@叶漂
这段代码只是一本书上的例子代码,在发布前,我把代码的结构作了一些调整。因为原来的代码结构不是很好读懂。
我以前没有太过注意foreach这个关键字的运行过程,只是了解会用。然而这次通过一个同事的提问,才注意到在foreach关键字中in后面的对象都是继承自一个接口IEnumerable(包括IList、ArrayList,应该还包括数组)。
    回复  引用  查看    

#3楼  2006-07-29 09:51 海蓝      

搞了半天不关foreach的事,是in在其中起作用
in是一个很灵活的操作符,它并没有限定操作符后面的对象一定实现了IEnumerable接口或是一个数组,只要前者的类型与后者中的元素类型一致,或前者是后者中的元素类型的子类型即可
    回复  引用  查看    

#4楼  2006-07-31 08:10 abeen      

"搞了半天不关foreach的事,是in在其中起作用
in是一个很灵活的操作符,它并没有限定操作符后面的对象一定实现了IEnumerable接口或是一个数组,只要前者的类型与后者中的元素类型一致,或前者是后者中的元素类型的子类型即可 "
也就是说在 foreach (type identifier in expression) statement中
expression和identifier的必须是兼容的。即:expression和identifier类型一至或是identifier的派生类。
    回复  引用  查看    

#5楼  2006-07-31 09:42 海蓝      

@abeen
谢谢你的指正

当时写了一点愚见后赶着出去,后来想了一下最后一句话是错的,今天看到你已经指出来了。完整的正确的说法应该是:

in是一个很灵活的操作符,它并没有限定操作符后面的对象一定实现了IEnumerable接口或是一个数组,只要后者中的元素类型与前者的类型一致,或是前者的子类型即可
    回复  引用  查看    

#6楼  2006-07-31 09:59 peng [未注册用户]

在 foreach (type identifier in expression) statement中expression对象只要实现了GetEnumerator,MoveNext,Reset方法和Current 成员就可以.
MSDN中解释如下
In C#, it is not strictly necessary for a collection class to inherit from IEnumerable and IEnumerator in order to be compatible with foreach; as long as the class has the required GetEnumerator, MoveNext, Reset, and Current members, it will work with foreach

可以见得foreach的工作原理,所以楼猪调试得到这样执行步骤也很正常.楼猪还想深入了解一点就看看foreach的IL实现吧,会更加清楚的
但是想使用foreach的对象就要实现上面几个方法不方便,所以在C#2.0中多加了一个yield关键字,有兴趣查查MSDN
    回复  引用    

#7楼  2006-08-01 11:00 Anders06      

“这段代码只是一本书上的例子代码,”

可见写书的人怎么不负责任了,这样糟糕的代码估计会误倒好多新人,连个越界判断都没有,还有当分配的数组大小不够用了该怎么办...

自己大学时做过这样的练习,考虑的都要比它仔细,虽然那时还能嫩,无语啊。。。。。
    回复  引用  查看    

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      


相关链接: