C# foreach详解 涉及迭代器的内容 IEnumerable与其泛型的实现

var lstStr = new List<string> { "a", "b" };
   foreach (var str in lstStr)
      {
        Console.WriteLine(str);
      }

//这是foreach的使用
//实际上内部是这样的

var lstStr = new List<string> {"a", "b"};
   IEnumerator<string> enumeratorLst = lstStr.GetEnumerator();
   while (enumeratorLst.MoveNext())
      {
        Console.WriteLine(enumeratorLst.Current);
      }

原本的话我们是需要先用一个实现IEnumerator 然后一个类实现IEnumerable(里面有GetEnumerator方法) 这样就可以对实现了IEnumerable的类使用foreach。 现在有一个很简单的方法,不需要一个类实现IEnumerator,直接使用一个实现了IEnumerable的类来使用foreach。要用到yield return。因为yield return 会自动将返回值当做Enumerator来处理,所有它直接返回了一个经过处理得IEnumerator。

好下面上我的代码

using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 双列表。即有两个一对一关系的列表需要维护时使用此类。
/// </summary>
/// <typeparam name="A"></typeparam>
/// <typeparam name="B"></typeparam>
public class DoubleList<A, B>:IEnumerable<KeyValuePair<A,B>> {

    List<A> listA;
    List<B> listB;

    /// <summary>
    /// 包含的对称双列表中,一条列表所含有的元素个数
    /// </summary>
    int Count
    {
        get { return listA.Count; }
    }

    int Capacity
    {
        get { return listA.Capacity; }
    }

    #region 构造函数
    /// <summary>
    /// 空参数的构造函数
    /// </summary>
    public DoubleList()
    {
        listA = new List<A>();
        listB = new List<B>();
    }
    /// <summary>
    /// 带有初始值的构造函数
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    public DoubleList(A a,B b)
    {
        listA = new List<A>();
        listB = new List<B>();
        listA.Add(a);
        listB.Add(b);
    }

    public DoubleList(List<A> a , List<B> B)
    {
        if(a.Count == B.Count)
        {
            listA = a;
            listB = B;
        }
        else
        {
            listA = new List<A>();
            listB = new List<B>();
        }
    }
    #endregion
    #region 迭代器
    public KeyValuePair<A,B> this[int i]
    {
        get {
            KeyValuePair<A, B> kv = new KeyValuePair<A, B>(listA[i],listB[i]);
            return kv;
        }
    }
    #endregion
    public void Add(A a , B b)
    {
        listA.Add(a);
        listB.Add(b);
    }
    /// <summary>
    /// 传进来两个列表,加到本双列表中。%%注意两个列表的长度要相等。
    /// </summary>
    /// <param name="listOfA"></param>
    /// <param name="listOfB"></param>
    public void AddRange(List<A> listOfA, List<B> listOfB)
    {
        //如果传进来的两个数组的长度不对称,那么这次操作无效。
        if (listOfA.Count != listOfB.Count) return; 
        //传进来的两个数组长度对称,那么这次操作有效。
        foreach (var ss in listOfA)
        {
            listA.Add(ss);
        }
        foreach (var ss in listOfB)
        {
            listB.Add(ss);
        }
    }

    public void Remove(A a, B b)
    {
        listA.Remove(a);
        listB.Remove(b);
    }

    public void RemoveRange(List<A> listOfA,List<B> listOfB)
    {
        //如果传进来的两个数组的长度不对称,那么这次操作无效。
        if (listOfA.Count != listOfB.Count) return;
        //传进来的两个数组长度对称,那么这次操作有效。
        foreach (var ss in listOfA)
        {
            listA.Remove(ss);
        }
        foreach (var ss in listOfB)
        {
            listB.Remove(ss);
        }
    }

    public void RemoveAt(int index)
    {
        listA.RemoveAt(index);
        listB.RemoveAt(index);
    }
    public bool ContainsFirst(A a)
    {
        return listA.Contains(a);
    }
    public bool ContainsSecond(B b)
    {
        return listB.Contains(b);
    }
    public void Clear()
    {
        listA.Clear();
        listB.Clear();
    }

    public IEnumerator<KeyValuePair<A, B>> GetEnumerator()
    {
        for (int i = 0; i < listA.Count; i++)
        {
            yield return new KeyValuePair<A, B>(listA[i], listB[i]);
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        for (int i = 0; i < listA.Count; i++)
        {
            yield return new KeyValuePair<A, B>(listA[i], listB[i]);
        }
    }
}

注意,这里我使用了泛型接口IEnumerable<KeyValuePair<A,B>>  ,这个就是影响你GetEnumerator() 的返回。

形象点说哈

1、如果我使用了非泛型的接口IEnumerable 然后正常实现了GetEnumerator()

现在我对这个类的对象使用foreach你会看到

这里会自动将其当做默认的object类型来处理,而后面我需要强转,看到没有,这样很麻烦。

2、但是我使用了泛型的接口IEnumerable<KeyValuePair<A,B>>

接下来神奇的事情发生了  当当当当~~

 

 

%%:哈哈 它说强转是多余的,我可以直接将item当做我设置的keyvaluepair类型来使用。

好了,结束。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值