为什么要用扩展方法
在说什么是扩展方法之前我们先来说说为什么要用扩展方法。
首先我们定义一个??类:
DateTime BirthTime { ;
DateTime? DeathTime { ;
}
加入这个类来自第三方的dll引用,且现在我们需要添加一个方法??获取年龄。你可能会想到自己定一个子类继承:
(DeathTime.Value - BirthTime).Days /
(DateTime.Now - BirthTime).Days /
是的,这样可以实现我们的需求。不过实现新增的方法就去继承真的是最合适的吗()??如果上面定义的密封类呢?? Person?,这个时候是不能继承的,我们只能另想办法。
随意写个静态类:
(person.DeathTime.Value - person.BirthTime).Days /
(DateTime.Now - person.BirthTime).Days /
然后调用??,是的看似不错。可是这和我们说的扩展方法有什么关系呢?下面就是见证奇迹的时候了。

其他的任何地方都不变,唯一变化的是在参数前面加里this关键字。对,是的,仅仅如此它就变成了我们今天要讲的扩展方法。
调用如:? age = p.GetAge();?相比上面的??更简单明了。
这里我们说的是在需要扩展密封类的方法时,我们可以使用到扩展方法。还有一种情况就是,在需要扩展接口的时候时候我们更加需要。比如,需要扩展IList的排序。我们要么写个扩展方法,要么是继承实现接口()。我想你心中已经有了答案选择哪种方式。
扩展方法到底是什么
我们看到上面使用的扩展方法,有没有感觉很神奇。仅仅多添加了一个this关键字就直接可以当成扩展方法使用了。那扩展方法到底是什么东东,看了上面代码好像和静态方法有着说不清道不明的关系。下面我们继续分析:
分别定义一个静态方法和一个扩展方法
(person.DeathTime.Value - person.BirthTime).Days /
(DateTime.Now - person.BirthTime).Days / </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> GetAge(<span style="color: #0000ff;">this</span><span style="color: #000000;"> Person person)
{
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (person.DeathTime.HasValue)
</span><span style="color: #0000ff;">return</span> (person.DeathTime.Value - person.BirthTime).Days / <span style="color: #800080;">365</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">else</span>
<span style="color: #0000ff;">return</span> (DateTime.Now - person.BirthTime).Days / <span style="color: #800080;">365</span><span style="color: #000000;">;
}</span></pre>
分别调用:
p = Person() { BirthTime = DateTime.Parse( age == ExtensionClass.GetAge2(p);
编译后的IL代码:

我们看到反编译成IL之后发现两者并无不同。所以,我理解成()。且?
扩展方法可以做些什么
IsNullOrEmpty(
调用:?
str = isNull = str.IsNullOrEmpty();
?感觉相比期静态方法调用要优雅,更接近我们的自然语言。
DateTime? MyToDateTime( (
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 转double
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="str"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">double</span> MyToDouble(<span style="color: #0000ff;">this</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> str)
{
</span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(str))
</span><span style="color: #0000ff;">return</span> -<span style="color: #800080;">1</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">else</span>
<span style="color: #0000ff;">return</span> <span style="color: #0000ff;">double</span><span style="color: #000000;">.Parse(str);
}
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 转int
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="str"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> MyToInt(<span style="color: #0000ff;">this</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> str)
{
</span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(str))
</span><span style="color: #0000ff;">return</span> -<span style="color: #800080;">1</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">else</span>
<span style="color: #0000ff;">return</span> <span style="color: #0000ff;">int</span><span style="color: #000000;">.Parse(str);
}
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 指示指定的字符串是 null 还是 System.String.Empty 字符串。
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="str"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">bool</span> IsNullOrEmpty(<span style="color: #0000ff;">this</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> str)
{
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(str);
}
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 如果字符串为null,则返回空字符串。(否则返回原字符串)
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="str"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">string</span> GetValueOrEmpty(<span style="color: #0000ff;">this</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> str)
{
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (str.IsNullOrEmpty())
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">string</span><span style="color: #000000;">.Empty;
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> str;
}</span></pre>
上面所有的都只是扩展方法的附加用处,扩展方法真正的威力是为Linq服务的(),实现链式编程。下面我们自己来实现所谓的链式编程:
初始化?
List persons = List Person(){ BirthTime=DateTime.Parse( Person(){ BirthTime=DateTime.Parse( Person(){ BirthTime=DateTime.Parse(),DeathTime=DateTime.Parse( Person(){ BirthTime=DateTime.Parse( Person(){ BirthTime=DateTime.Parse( Person(){ BirthTime=DateTime.Parse( Person(){ BirthTime=DateTime.Parse(
需求:1.查询活人。2.按出生日期排序
IList MyWhere( IList list,Func> newList = List ( item </span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 升序排序
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><typeparam name="T"></typeparam></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="list"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="func"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> IList<T> MyOrderBy<T>(<span style="color: #0000ff;">this</span> IList<T> list,DateTime><span style="color: #000000;"> func)
{
</span><span style="color: #0000ff;">if</span> (list.Count() <= <span style="color: #800080;">1</span><span style="color: #000000;">)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = <span style="color: #800080;">0</span>; i < list.Count(); i++<span style="color: #000000;">)
{
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> j = i + <span style="color: #800080;">1</span>; j < list.Count(); j++<span style="color: #000000;">)
{
</span><span style="color: #0000ff;">var</span> item1 = list[j - <span style="color: #800080;">1</span><span style="color: #000000;">];
</span><span style="color: #0000ff;">var</span> item2 =<span style="color: #000000;"> list[j];
</span><span style="color: #0000ff;">if</span> ((func(item1) - func(item2)).Ticks > <span style="color: #800080;">0</span><span style="color: #000000;">)
{
list[j </span>- <span style="color: #800080;">1</span>] =<span style="color: #000000;"> item2;
list[j] </span>=<span style="color: #000000;"> item1;
}
}
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
}
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 降序排序
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><typeparam name="T"></typeparam></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="list"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="func"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> IList<T> MyOrderByDescending<T>(<span style="color: #0000ff;">this</span> IList<T> list,DateTime><span style="color: #000000;"> func)
{
</span><span style="color: #0000ff;">if</span> (list.Count() <= <span style="color: #800080;">1</span><span style="color: #000000;">)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = <span style="color: #800080;">0</span>; i < list.Count(); i++<span style="color: #000000;">)
{
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> j = <span style="color: #800080;">1</span>; j < list.Count() - i; j++<span style="color: #000000;">)
{
</span><span style="color: #0000ff;">var</span> item1 = list[j - <span style="color: #800080;">1</span><span style="color: #000000;">];
</span><span style="color: #0000ff;">var</span> item2 =<span style="color: #000000;"> list[j];
</span><span style="color: #0000ff;">if</span> ((func(item1) - func(item2)).Ticks < <span style="color: #800080;">0</span><span style="color: #000000;">)
{
list[j </span>- <span style="color: #800080;">1</span>] =<span style="color: #000000;"> item2;
list[j] </span>=<span style="color: #000000;"> item1;
}
}
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
}
}</span></pre>
调用:()
newPersons = persons.MyWhere(t => t.DeathTime == ).MyOrderByDescending(t => ( item
就是如此简单的实现了所谓的函数式编程。结果图如下:

这样一句代码搞定所有逻辑,像自然语言般的流畅。其实.net为IEnumerable实现了这样的扩展,如:

执行结构和上面一模一样。
其实扩展方法也可以当成静态方法来使用:
p1 = ExtensionClass.MyWhere(persons,t => t.DeathTime == p2 = ExtensionClass.MyOrderByDescending(p1,t => p3 = ExtensionClass.MyOrderBy(p2,t => t.BirthTime);
C#代码:
? 
反编译C#的代码:()

反编译的IL代码:

虽然编译后的代码是一样的,但是做为程序员的我们更喜欢哪种方式呢? 
我们在对扩展方法的怎么使用疑惑或者忘记了规则的时候,我们不用去查找资料说:
- 第一个参数是要扩展或者要操作的类型,这称为"被扩展的类型"
- 为了指定扩展方法,要在被扩展的类型名称前面附加this修饰符
- 要将方法作为一个扩展方法来访问,要用using指令导入扩展类型的命名空间,或者使扩展类型和调用代码在同一个命名空间中.
全部代码:
<span style="color: #0000ff;">namespace<span style="color: #000000;"> test
{
</span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Program
{
</span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span><span style="color: #000000;">[] args)
{
</span><span style="color: #008000;">/*</span><span style="color: #008000;">
* 1.工具类
* 2.链式编程
</span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">string</span> str = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">var</span> isNull =<span style="color: #000000;"> str.IsNullOrEmpty();
</span><span style="color: #0000ff;">var</span> p = <span style="color: #0000ff;">new</span> Person() { BirthTime = DateTime.Parse(<span style="color: #800000;">"</span><span style="color: #800000;">1990-07-19</span><span style="color: #800000;">"</span><span style="color: #000000;">) };
</span><span style="color: #0000ff;">var</span> age =<span style="color: #000000;"> p.GetAge();
age </span>=<span style="color: #000000;"> ExtensionClass.GetAge2(p);
List</span><Person> persons = <span style="color: #0000ff;">new</span> List<Person><span style="color: #000000;">()
{
</span><span style="color: #0000ff;">new</span> Person(){ BirthTime=DateTime.Parse(<span style="color: #800000;">"</span><span style="color: #800000;">1990-01-19</span><span style="color: #800000;">"</span><span style="color: #000000;">)},</span><span style="color: #0000ff;">new</span> Person(){ BirthTime=DateTime.Parse(<span style="color: #800000;">"</span><span style="color: #800000;">1991-06-19</span><span style="color: #800000;">"</span><span style="color: #000000;">)}
};
</span><span style="color: #0000ff;">var</span> newPersons = persons.MyWhere(t => t.DeathTime == <span style="color: #0000ff;">null</span>).MyOrderByDescending(t =><span style="color: #000000;"> t.BirthTime);
</span><span style="color: #0000ff;">var</span> p1 = ExtensionClass.MyWhere(persons,t => t.DeathTime == <span style="color: #0000ff;">null</span><span style="color: #000000;">);
</span><span style="color: #0000ff;">var</span> p2 = ExtensionClass.MyOrderByDescending(p1,t =><span style="color: #000000;"> t.BirthTime);
</span><span style="color: #0000ff;">var</span> p3 = ExtensionClass.MyOrderBy(p2,t =><span style="color: #000000;"> t.BirthTime);
</span><span style="color: #0000ff;">foreach</span> (<span style="color: #0000ff;">var</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> newPersons)
{
Console.WriteLine(item.BirthTime);
}
Console.ReadKey();
}
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">sealed</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> Person
{
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 出生日期
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #0000ff;">public</span> DateTime BirthTime { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 死亡日期
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #0000ff;">public</span> DateTime? DeathTime { <span style="color: #0000ff;">get</span>; <span style="color: #0000ff;">set</span><span style="color: #000000;">; }
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">public class MyPerson : Person
</span><span style="color: #008000;">//</span><span style="color: #008000;">{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> public int GetAge()
</span><span style="color: #008000;">//</span><span style="color: #008000;"> {
</span><span style="color: #008000;">//</span><span style="color: #008000;"> if (DeathTime.HasValue)
</span><span style="color: #008000;">//</span><span style="color: #008000;"> return (DeathTime.Value - BirthTime).Days / 365;
</span><span style="color: #008000;">//</span><span style="color: #008000;"> else
</span><span style="color: #008000;">//</span><span style="color: #008000;"> return (DateTime.Now - BirthTime).Days / 365;
</span><span style="color: #008000;">//</span><span style="color: #008000;"> }
</span><span style="color: #008000;">//</span><span style="color: #008000;">}</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> ExtensionClass
{
</span><span style="color: #808080;">///</span> <span style="color: #808080;"><summary></span>
<span style="color: #808080;">///</span><span style="color: #008000;"> 按条件查询
</span><span style="color: #808080;">///</span> <span style="color: #808080;"></summary></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><typeparam name="T"></typeparam></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="list"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><param name="func"></param></span>
<span style="color: #808080;">///</span> <span style="color: #808080;"><returns></returns></span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> IList<T> MyWhere<T>(<span style="color: #0000ff;">this</span> IList<T> list,DateTime><span style="color: #000000;"> func)
{
</span><span style="color: #0000ff;">if</span> (list.Count() <= <span style="color: #800080;">1</span><span style="color: #000000;">)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = <span style="color: #800080;">0</span>; i < list.Count(); i++<span style="color: #000000;">)
{
</span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> j = <span style="color: #800080;">1</span>; j < list.Count() - i; j++<span style="color: #000000;">)
{
</span><span style="color: #0000ff;">var</span> item1 = list[j - <span style="color: #800080;">1</span><span style="color: #000000;">];
</span><span style="color: #0000ff;">var</span> item2 =<span style="color: #000000;"> list[j];
</span><span style="color: #0000ff;">if</span> ((func(item1) - func(item2)).Ticks < <span style="color: #800080;">0</span><span style="color: #000000;">)
{
list[j </span>- <span style="color: #800080;">1</span>] =<span style="color: #000000;"> item2;
list[j] </span>=<span style="color: #000000;"> item1;
}
}
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> list;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> GetAge2(Person person)
{
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (person.DeathTime.HasValue)
</span><span style="color: #0000ff;">return</span> (person.DeathTime.Value - person.BirthTime).Days / <span style="color: #800080;">365</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">else</span>
<span style="color: #0000ff;">return</span> (DateTime.Now - person.BirthTime).Days / <span style="color: #800080;">365</span><span style="color: #000000;">;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> GetAge(<span style="color: #0000ff;">this</span><span style="color: #000000;"> Person person)
{
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (person.DeathTime.HasValue)
</span><span style="color: #0000ff;">return</span> (person.DeathTime.Value - person.BirthTime).Days / <span style="color: #800080;">365</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">else</span>
<span style="color: #0000ff;">return</span> (DateTime.Now - person.BirthTime).Days / <span style="color: #800080;">365</span><span style="color: #000000;">;
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">bool</span> IsNullOrEmpty(<span style="color: #0000ff;">this</span> <span style="color: #0000ff;">string</span><span style="color: #000000;"> str)
{
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">string</span><span style="color: #000000;">.IsNullOrEmpty(str);
}
}
}
本文以同步至《》 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|