有关C#中的foreach

在编写C#代码时,我们会发现使用foreach循环会比使用for循环方便,不需要进行数据类型的强制转换,不需要使用下标!通过帮助文档的查看可知,如果要对一个对象使用foreach进行循环的话则此对象的类型必须拥有GetEnumerator方法,此方法是在IEnumerable接口下的,但是否实现此接口无所谓!GetEnumerator方法需要返回一个IEnumerator的实例,因为在进行foreach遍历时会使用到一个属性:Current和一个方法:MoveNext!以下是带有注释的源代码:

using System;
using System.Collections;

namespace ConTest01
{
 /// <summary>
 /// Class1 的摘要说明。
 /// </summary>
 class Class1
 {
  /// <summary>
  /// 应用程序的主入口点。
  /// </summary>
  [STAThread]
  static void Main(string[] args)
  {
   Persons p = new Persons("jack","tom","marry","mike");
   foreach(string s in p)
   {
    Console.WriteLine(s);
   }
  }
 }

 public class Persons
 {
  public string[] m_Names;

  public Persons(params string[] Names)
  {
   this.m_Names = new string[Names.Length];
   Names.CopyTo(this.m_Names,0);
  }

  public string this[int index]
  {
   get
   {
    return this.m_Names[index];
   }
   set
   {
    this.m_Names[index] = value;
   }
  }

  #region IEnumerable 成员

  //如果此类需要被foreach遍历则必须拥有此方法,至于是否实现IEnumerable接口倒是无所谓
  public IEnumerator GetEnumerator()
  {
   //返回一个IEnumerator的实例
   return new PersonsEnumerator(this);
  }

  #endregion

 }

 public class PersonsEnumerator : IEnumerator
 {
  private int index = -1;
  private Persons P;

  public PersonsEnumerator(Persons P)
  {
   this.P = P;
  }

  #region IEnumerator 成员

  //重置方法
  public void Reset()
  {
   this.index = -1;
  }

  //得到当前值的属性,是只读,因此在进行foreach遍历时不能修改遍历到的元素内容
  public object Current
  {
   get
   {
    return this.P[index];
   }
  }

  //将当前实例内部的索引前进一位,并判断前进后是否还有元素
  public bool MoveNext()
  {
   int tempIndex = ++this.index;
   if(tempIndex >= this.P.m_Names.Length)
   {
    return false;
   }
   else
   {
    return true;
   }
  }
  #endregion

 }

 

 

 

 

要对一些对象做添加修改删除处理。别的到没什么,删除时出现了点问题似的。
 
  因为是从一个类的集合中删除掉一个元素。这样就要遍历整个集合,而foreach正是为遍历准备的新玩意。自然而然用上了。于是代码类似如下:
 
string temp = name.Text; // 从TextBox中读出数据
foreach (LCourse cou in Data.myCourse) // 在List 中遍历
{
if (cou.name == temp) // 判断cou的名字匹配
{
Data.myCourse.Remove(cou); // 匹配的即为要删除的,从列表中去除
break; // 跳出循环
}
}

很容易就想到这么用foreach,貌似也没错误。但是印象中关于foreach的注意点就是只适用于遍历读取,不能修改。上边的代码却删除成功。这样,矛盾的种子就种在了心里,到底foreach是个什么东西?

过程:

看了MSDN文档,可是文档里的示例用到foreach时都是遍历读取每个元素,所以帮助不大。相关测试,异常,编译错误反倒有很大用处。

过程细节和总结:

1 ,自定义整型数组然后遍历修改

foreach(int myint in myArray)

{ myint+=8;}

错误 1 “myint”是一个“foreach 迭代变量”,无法为它赋值 G:/TEST/VS..C#/testforeach/Program.cs 15 27 testforeach
2 ,自定义类,在类中定义函数对私有成员进行操作,然后遍历类对象并调用函数

public class MyClass // 自定义的测试类
{
private int i = 0;
public void change()
{
i = 98;
}
public override string ToString()
{
return i.ToString();
}
}

MyClass[] myTest = new MyClass[10]; // 测试代码片段
foreach (MyClass mc in myTest)
{
mc.change();
Console.WriteLine(mc.ToString());
}

通过了编译,但是抛出异常,NullRefferenceException,未将对象引用设置到对象的实例。

3 ,就是像开头测试的例子,稍有改动,移除后不用break跳出

List myString = new List ();

myString.Add("ab");
myString.Add("cd");
foreach (string s in myString)
{
myString.Remove(s);
}

编译通过了,但运行时抛出异常,InvalidOperationException,集合已修改;可能无法执行枚举操作。

通过上面三个测试例子和开头的实际例子,我貌似看到了foreach的某种东西。

第一,不能修改的是foreach引用变量,因为它是引用的,对它的修改没有意义也没有作用,它就像一个c/c++指针那样对集合中的元素进行指向引用;我们能通过引用看到它,但是没有能力动它。

第二,in之前的变量是引用变量,但in之后的集合确是实实在在的,所以可以对它操作,像.ADD();REMOVE()等方法可以使用。

第三,foreach引用变量大概是通过地址指向后面的集合(我猜想跟c/c++的指针很像),当修改了集合的元素时,地址可能发生某种改变,所以不跳出循环继续遍历时,就可能出现引用找不到的情况。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值