• 【IEnumerable】扩展方法的使用 C# Charles


       直接进入主题吧...


           IEnumerable : 公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。 好吧,迭代,我就理解成循环,这些名词真晦涩,没意思
           今天看的是 Using Extension Methods ,使用"扩展方法"。俺都开始看英文文档了,得瑟中...
           所谓扩展方法,是对类型的扩展。如对string扩展一个GotoHell(); 方法,可以这样用  “damn”.GotoHell();
           如何实现呢,咱创建一个新的类,叫做StringExtend,有这样一个方法,
            public static string GotoHell(this string str)
            {
                 return str+"GotoHell";
             }
            然后在另一处调用(同一个命名空间哦),"Damn ".GotoHell();  输出的值为:“Damn GotoHell” (由此看出,我心情却是不好啊)

            这是一般类型的扩展方法,似乎与主题那不搭边呢,好吧,我跑题了。
            IEnumerable 我也不管他是什么东西,反正就理解像是一个列表的东西。而实际上List是继承的IEnumerable。
            为了使程序更形象,于是俺创建一个实体类:
            public class Product
           {
              public string Name { get; set; }
              public string Category { get; set; }
              public decimal Price { get; set; }
          }
          这儿又得跳跃一下,Using Automatically Implemented Properties。也就是public string Name{get;set;} 对应的英文定义了。
          翻译为:自动实现的属性。为啥叫自动实现的属性,都实现了哪些呢? 如果不这样写,那就需要这样:
          get{ return name; } // 这里还需要创建一个name变量
          set{ name=value;}
          确实比较繁琐,
    耦合性也稍微高一些,同时效率也稍微低一些。
          【Tag1】现在我们来点数据:
          IEnumerable<Product> products = new List<Product> {
                new Product{Name="one",Category="rose",Price=56},
                new Product{Name="two",Category="jack",Price=55},
                new Product{Name="three",Category="jack",Price=54}
                };
           上面说过了,IEnum... 就像是个列表的东西,List 实现了它,这样赋值不足为过吧。
           那现在我要筛选出 Category 为jack 的数据,怎么办呢。咱新建一个List temp ? 对吧,怕啥啊,不就浪费点内存吗,咱有的是。
           好吧,我以前就是这么想的,而如今,我觉得那样做,太TM操蛋了。
          ----------------------
           我新建一个类:MyextendClass
           public static IEnumerable<Product> FilterByCategory(this IEnumerable<Product> productEnum,string categoryParam)
           {
                  foreach(Product pro in productEnum)   // 这里我习惯性写成 foreach(var item in productEnum)
                  {
                      if(pro.Category==categoryParam)
                      {
                          yield return pro;  // yield 是什么鸟玩意儿啊? 我只知道他用在迭代器里面,告诉他这里结束了,下次你来迭代的时候往下一个迭代走。同时呢,他发现一个东西就立即返回过去,不要等待集合装入完毕,据说效 率杠杠滴哦。这是我的理解,有大虾的话,请留言更正。
                       }
                   }
           }
          然后,就调用了:products.
    FilterByCategory("jack"); 好了,这样就获取了 category 为 jack 的列表,你想怎么处理输出都是你的事情了。
         再想想,如果我要计算jack分类的Price的总和呢?如果N多地方出现这种情况,难道我们都要重新写方法吗?话说,就算写好了,以后也不好维护呢。好吧,咱再扩展一个呗:
    public static decimal TotalPrice(this IEnumerable<Product> productEnum)
    {
        decimal total=0;
        foreach(var item in productEnum)
        {
             total+=item.Price;
         }
         return total;
    }
    Wonderful,这样我们就这样调用:products.FilterByCategory("jack").TotalPrice(); 是不是很方便,以后要修改这部分代码页相当方便。
    只要一处扩展这个方法,到处都可以用。维护固然就很方便了。

    有这么一种情况,我想按某种方式过滤出数据,可是我现在还不知道要怎么过滤。我需要把这一层写好先。然后有时间我再去独立的思考那一方面的逻辑。委托? 我给你参数和我需要的返回值类型,之后你要干嘛干嘛去,我不管了(这不就是汉语中委托的意思么,呵呵)。
    这里有这样一个委托: Func<in T,out TResult> 给个T的参数,返回TResult 类型的值(话说对 泛型 了解的还不够深刻,不管乱解释,改天我再去瞅瞅)。
    好了,写扩展方法咯:
    public static IEnumerable<Product> Filter(this IEnumerable<product> productEnum,Func<Product,bool> selectorParam)
    {
        foreach(var item in productEnum){
             if(selectorParam(item)){
                  yield return item;
              }
        }
    }
    那委托都干了点啥呢?我们调用前给他赋予它的使命:
    Func<Product,bool> categoryfilter=delegate(Product pro){  reutrn pro.Category=="rose";  };
    products.Filter(categoryfilter); //终于得到rose了。
    有没有一种方式,再简化下这种委托呢?有的,Lamada (这个我也不是很熟,改天一并看了吧):
    Func<Product,bool> categoryfilter=pro=>pro.Category=="rose";
    (好吧,关于扩展方法我就看了这么些,输出结果为 两个 “jack” ,一个 “rose” . 这男女比例真的失衡了,这咋分啊。    )

    最后提一句,在【Tag1】的时候,IEnumerable 也可以写成 IList 或 其他类似的 继承了 IEnumerable 的类型或接口。

    通过使用 IEnumerable 可以定制适合自己开发过程中的基本逻辑,就像PS中录制动作一般,相当使用。

    又如一个例子:假设在B2C站中,商品详情页有商品评论,商品评论已经缓存了下来(我想这是必要的)。

            在显示评价时,有这样的需求,如果是置顶的则排在最前面,其次是精华评论,再者就是其他。

            方案a.我们可以使用正常的逻辑去处理,整出几十行代码。如果在其他使用类似的逻辑,只是过滤条件变了,我们又得重新写这部分的逻辑。

            方案b.如果我们新建一个扩展类,将这部分逻辑添加到扩展中。只需业务逻辑中添加几行代码便可实现需求。不仅从代码的美观上还是在系统的维护上都有很大的好处。
     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;

    namespace ConsoleTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                IList<RefModel> list = Init();
                IList<RefModel> list2 = list.Filter_Attr(r => r.IsTop == true && r.Sex == "boy").ToList();
                Console.WriteLine("-------------------过滤-----------------------");
                foreach (var item in list2)
                {
                    Console.WriteLine(item.Name + "  " + (item.IsTop ? "[T]  " : "") + (item.IsElite ? "[E]  " : "") + "[" + item.Sex + "]");
                }
                Console.WriteLine("-------------------重组:原顺序---------------------------");
                foreach (var item in list)
                {
                    Console.WriteLine(item.Name + "  " + (item.IsTop ? "[T]  " : "") + (item.IsElite ? "[E]  " : ""));
                }
                Console.WriteLine("-------------------重组:规则排序后----------------------------");
                list = list.Filter_Order().ToList();
                foreach (var item in list)
                {
                    Console.WriteLine(item.Name + "  " + (item.IsTop ? "[T]  " : "") + (item.IsElite ? "[E]  " : ""));
                }
                Console.ReadLine();
            }

            private static IList<RefModel> Init()
            {
                IList<RefModel> list = new List<RefModel>(){
                    new RefModel { Name = "charles", Sex = "boy", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles1", Sex = "girl", IsTop = true, IsElite = false },
                    new RefModel { Name = "charles2", Sex = "girl", IsTop = false, IsElite = true },
                    new RefModel { Name = "charles3", Sex = "boy", IsTop = false, IsElite = true },
                    new RefModel { Name = "charles4", Sex = "girl", IsTop = true, IsElite = false },
                    new RefModel { Name = "charles5", Sex = "girl", IsTop = false, IsElite = true },
                    new RefModel { Name = "charles6", Sex = "boy", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles7", Sex = "girl", IsTop = true, IsElite = false },
                    new RefModel { Name = "charles8", Sex = "boy", IsTop = false, IsElite = false },
                    new RefModel { Name = "charles9", Sex = "girl", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles10", Sex = "boy", IsTop = false, IsElite = false },
                    new RefModel { Name = "charles11", Sex = "boy", IsTop = false, IsElite = false },
                    new RefModel { Name = "charles12", Sex = "girl", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles13", Sex = "boy", IsTop = false, IsElite = false },
                    new RefModel { Name = "charles14", Sex = "boy", IsTop = false, IsElite = true },
                    new RefModel { Name = "charles15", Sex = "girl", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles16", Sex = "girl", IsTop = false, IsElite = false },
                    new RefModel { Name = "charles17", Sex = "boy", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles18", Sex = "boy", IsTop = false, IsElite = true },
                    new RefModel { Name = "charles19", Sex = "girl", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles20", Sex = "boy", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles21", Sex = "boy", IsTop = false, IsElite = false },
                    new RefModel { Name = "charles22", Sex = "girl", IsTop = true, IsElite = true },
                    new RefModel { Name = "charles23", Sex = "boy", IsTop = true, IsElite = false },
                    new RefModel { Name = "charles24", Sex = "boy", IsTop = true, IsElite = true }};
                return list;
            }
        }

        public class RefModel
        {
            public string Name { get; set; }
            public string Sex { get; set; }
            public bool IsTop { get; set; }
            public bool IsElite { get; set; }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleTest
    {
        public static class Filter
        {
            public static IEnumerable<RefModel> Filter_Attr(this IEnumerable<RefModel> list, Func<RefModel, bool> selectorParam)
            {
                foreach (var item in list)
                {
                    if (selectorParam(item))
                    {
                        yield return item;
                    }
                }
            }
    
            public static IEnumerable<RefModel> Filter_Order(this IEnumerable<RefModel> list)
            {
                IList<RefModel> topList = new List<RefModel>();
                IList<RefModel> eliteList = new List<RefModel>();
                IList<RefModel> elseList = new List<RefModel>();
                foreach (var item in list)
                {
                    if (item.IsTop)
                    {
                        topList.Add(item);
                        //yield return item;//Tag FX 
                    }
                    else if (item.IsElite)
                    {
                        eliteList.Add(item);
                    }
                    else
                    {
                        elseList.Add(item);
                    }
                }
                ///////////Tag X Start////////////
                foreach (var item in topList)
                {
                    yield return item;
                }
                ///////////Tag X End////////////
                foreach (var item in eliteList)
                {
                    yield return item;
                }
                foreach (var item in elseList)
                {
                    yield return item;
                }
    
            }
        }
    }

    运行结果:(部分)

        最后如果理解 yield 的用法,那么可以将上述代码中 Tag X 行取消注释,并将 Tag X Start 内的代码注释掉,将得到相同的结果。这样讲减少一层循环。虽然效率提高的微乎其微,但却如我博客Header所述:不积跬步无以至千里。

           

        如对你有帮助,轻轻地东东手指,Recomend Or Comment 。 你的支持是我的不断前行的动力。                             欢迎转载。

  • 相关阅读:
    STM32学习中出现的错误
    原码 反码 补码 移码
    LiauidCrystal
    gpio 的配置
    ARM7探究
    导轨控制问题
    A4988驱动42步进电机
    arduino驱动oled
    计算机组成原理
    arduino basic issue
  • 原文地址:https://www.cnblogs.com/shenchaoming/p/IEnumerable.html
Copyright © 2020-2023  润新知