直接进入主题吧...
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 。 你的支持是我的不断前行的动力。 欢迎转载。