17. 阿宝陪你学C#【枚举器和迭代器】:面馆里的 “食材分拣流水线” 大揭秘!

阿宝陪你学C#【枚举器和迭代器】:面馆里的 “食材分拣流水线” 大揭秘!

嘿哟嘿!各位立志成为编程大侠的面条侠们!我是你们的好朋友阿宝!上次咱们聊到 C# 里超厉害的泛型,那家伙就像面馆里的万能百宝囊,啥食材都能装!今天阿宝要带你们深入面馆后厨,探索超神秘的 “食材分拣流水线”——C# 里的枚举器和迭代器!学会它们,处理数据就跟我耍功夫一样轻松!

一、枚举器和可枚举类型:后厨的食材分拣员

在咱们热闹非凡的面馆里,每天都有各种各样的食材到货,面条、青菜、牛肉、鸡蛋…… 堆得满满当当。要是想把这些食材挨个拿出来处理,就需要一个 “食材分拣员”,这在 C# 里就是枚举器!而装食材的大箱子,就好比可枚举类型。

可枚举类型能 “产出” 一系列数据,像施了魔法一样告诉枚举器:“从这里面把食材挨个拿出来吧!” 枚举器接到任务,就勤勤恳恳地按顺序把箱子里的食材一一取出,直到拿完为止。

C# 里很多类型天生就是可枚举的。比如数组,就像面馆里整齐排列的 “食材收纳架”;列表则像能随意添加食材的大篮子。来看个简单例子,用数组存储面馆里的几种面条:

string[] noodles = { "拉面", "刀削面", "热干面" };

这里的noodles数组就是可枚举类型,搭配枚举器就能轻松处理里面的每一种面条啦!

二、IEnumerator 接口:分拣员的 “工作证”

在面馆,可不是随便谁都能当食材分拣员,得有 “工作证” 才行!在 C# 世界里,IEnumerator接口就是枚举器的 “工作证”。实现了这个接口的类,就获得了 “合法” 分拣数据的资格。

IEnumerator接口有几个关键 “技能”:

  • MoveNext方法像分拣员的 “步伐”,调用它,分拣员就走到下一个食材旁;
  • Current属性如同分拣员手里的当前食材,通过它获取正在处理的数据;
  • Reset方法现在很少用,类似让分拣员回到起始位置,太麻烦,一般不这么干!

下面咱们自定义一个实现IEnumerator接口的简单枚举器类,来遍历上面的面条数组:

class NoodleEnumerator : IEnumerator
{
   private string[] noodles;
   private int position = -1;
   public NoodleEnumerator(string[] noodles)
   {
       this.noodles = noodles;
   }

   public object Current
   {
       get
       {
           if (position == -1 || position >= noodles.Length)
           {
               throw new InvalidOperationException();
           }
           return noodles[position];
       }
   }

   public bool MoveNext()
   {
       position++;
       return position < noodles.Length;
   }

   public void Reset()
   {
       position = -1;
   }
}

使用的时候这样操作:

string[] noodles = { "拉面", "刀削面", "热干面" };

NoodleEnumerator enumerator = new NoodleEnumerator(noodles);

while (enumerator.MoveNext())
{
   string currentNoodle = (string)enumerator.Current;
   Console.WriteLine(currentNoodle);
}

有了这个 “工作证”,枚举器就能把可枚举类型里的数据有条不紊地 “拿” 出来处理!

三、IEnumerable 接口:箱子的 “使用说明”

前面说可枚举类型是装食材的大箱子,那IEnumerable接口就是箱子上的 “使用说明”,它告诉大家:“这箱子里的东西能挨个拿出来用!”

实现IEnumerable接口的类,必须提供GetEnumerator方法,这就像箱子的 “开锁钥匙”,调用它就能拿到对应的枚举器。而且 C# 里超方便的foreach循环,背后就是靠IEnumerableIEnumerator接口合作实现的!

我们让上面的面条数组 “升级”,实现IEnumerable接口:

class NoodleCollection : IEnumerable
{
   private string[] noodles;

   public NoodleCollection(string[] noodles)
   {
       this.noodles = noodles;
   }
   public IEnumerator GetEnumerator()
   {
       return new NoodleEnumerator(noodles);
   }
}

使用foreach循环遍历就超简单啦:

string[] noodles = { "拉面", "刀削面", "热干面" };

NoodleCollection noodleCollection = new NoodleCollection(noodles);
foreach (string noodle in noodleCollection)
{
   Console.WriteLine(noodle);
}

foreach会自动调用GetEnumerator拿到分拣员,再让分拣员用MoveNextCurrent,轻松遍历数据!

四、泛型枚举接口:更专业的分拣员团队

普通枚举器和接口像面馆里的普通分拣员,能完成基础工作。但有时我们需要更专业的分拣员,这就轮到泛型枚举接口登场!

IEnumerator<T>IEnumerable<T>是泛型枚举接口,T就像给分拣员指定专门处理的食材类型,避免拿错(防止类型错误),工作更高效!

用泛型枚举接口改写上面的面条示例:

class GenericNoodleEnumerator : IEnumerator<string>
{
   private string[] noodles;
   private int position = -1;

   public GenericNoodleEnumerator(string[] noodles)
   {
       this.noodles = noodles;
   }

   public string Current
   {
       get
       {
           if (position == -1 || position >= noodles.Length)
           {
               throw new InvalidOperationException();
           }
           return noodles[position];
       }
   }

   object IEnumerator.Current => Current;

   public bool MoveNext()
   {
       position++;
       return position < noodles.Length;
   }

   public void Reset()
   {
       position = -1;
   }

   public void Dispose()
   {
       // 这里如果有资源清理操作可以实现,一般简单场景为空
   }
}


class GenericNoodleCollection : IEnumerable<string>
{
   private string[] noodles;

   public GenericNoodleCollection(string[] noodles)
   {
       this.noodles = noodles;
   }

   public IEnumerator<string> GetEnumerator()
   {
       return new GenericNoodleEnumerator(noodles);
   }

   IEnumerator IEnumerable.GetEnumerator()
   {
       return GetEnumerator();
   }
}

使用起来同样方便:

string[] noodles = { "拉面", "刀削面", "热干面" };

GenericNoodleCollection genericNoodleCollection = new GenericNoodleCollection(noodles);
foreach (string noodle in genericNoodleCollection)
{
   Console.WriteLine(noodle);
}

这就像给分拣团队 “升级”,处理数据更准确!

五、迭代器:厨房里的 “自动传送带”

枚举器像人工分拣员,那迭代器就好比厨房里的 “自动传送带”,处理数据更轻松智能!

在 C# 里用yield关键字定义迭代器方法,yield就像给传送带下 “指令”,告诉它何时 “传送” 数据。执行到yield return就返回一个数据,记住状态,下次接着来!

比如遍历面馆特色菜品,用迭代器超简单:

IEnumerable<string> GetSpecialDishes()
{
   yield return "招牌牛肉面";
   yield return "酸辣粉";
   yield return "炸酱面";
}

调用的时候:

foreach (string dish in GetSpecialDishes())
{
   Console.WriteLine(dish);
}

比普通枚举器方便太多!

六、常见迭代器模式:传送带的不同玩法

面馆厨房里,“自动传送带”(迭代器)有多种玩法!
简单迭代器:像基础传送带,按序传送食材(数据)。比如遍历面条列表:

IEnumerable<string> SimpleNoodleIterator()
{
   string[] noodles = { "拉面", "刀削面", "热干面" };
   foreach (string noodle in noodles)
   {
       yield return noodle;
   }
}

筛选迭代器:带 “筛选功能” 的传送带。比如只处理新鲜食材:

class Ingredient
{
   public string Name { get; set; }
   public bool IsFresh { get; set; }
}

IEnumerable<Ingredient> FilterFreshIngredients(IEnumerable<Ingredient> ingredients)
{
   foreach (Ingredient ingredient in ingredients)
   {
       if (ingredient.IsFresh)
       {
           yield return ingredient;
       }
   }
}

转换迭代器:能让食材 “变身”!比如把食材名字转大写:

IEnumerable<string> TransformIngredientNames(IEnumerable<string> ingredients)
{
   foreach (string ingredient in ingredients)
   {
       yield return ingredient.ToUpper();
   }
}

七、产生多个可枚举类型:多条传送带同时工作

面馆生意火爆时,需同时处理多批食材,相当于产生多个可枚举类型!

定义多个迭代器方法,返回不同可枚举类型。比如处理蔬菜和肉类:

IEnumerable<string> GetVegetables()
{
   yield return "青菜";
   yield return "白菜";
   yield return "豆芽";
}

IEnumerable<string> GetMeats()
{
   yield return "牛肉";
   yield return "猪肉";
   yield return "鸡肉";
}

可以组合使用,超灵活!

八、将迭代器作为属性:把传送带变成随时可用的 “工具”

在面馆,常用工具放顺手处方便使用。C# 里也能把迭代器作为属性,像把 “自动传送带” 变成随手工具!

定义 “今日特价菜品” 属性:

class Restaurant
{
   public IEnumerable<string> SpecialDishes
   {
       get
       {
           yield return "特价牛肉面";
           yield return "优惠酸辣粉";
       }
   }
}

使用时:

Restaurant restaurant = new Restaurant();

foreach (string dish in restaurant.SpecialDishes)
{
   Console.WriteLine(dish);
}

随时获取想要的数据!

九、迭代器的本质:传送带背后的 “功夫奥秘”

说了这么多,迭代器本质是啥?其实 C# 编译器会偷偷生成一个状态机,像传送带背后的 “操控大师”,记住迭代器执行状态。每次调用迭代器方法,状态机按状态操作,遇到yield return返回数据并保存状态,超厉害!虽然看不到它工作,但正因如此,迭代器才如此高效灵活!

十、总结:成为数据处理的功夫大师!

好啦面条侠们!今天咱们深入探索了 C# 里枚举器和迭代器的神奇世界,从食材分拣员到自动传送带,再到背后的功夫奥秘,还看了超多代码示例!它们是编程路上的得力助手,掌握它们,处理数据就像我阿宝打坏人一样轻松!下次写代码,别忘了这些 “功夫秘籍”!要是还有疑惑,随时来面馆找阿宝,咱们一起修炼,成为数据处理的超级大侠!下次还有更多超有趣的 C# 知识,不见不散!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿蒙Armon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值