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

   直接进入主题吧...


       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 。 你的支持是我的不断前行的动力。                             欢迎转载。

转载于:https://www.cnblogs.com/shenchaoming/archive/2013/03/25/IEnumerable.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值