扩展方法使用小结

随着.Net Framework一路走来,已经让广大开发人员体验到快速开发的甜头,这得益于.Net Framework为我们提供了更高层次的封装,开发人员不必关心底层的Win32 API及其繁琐的调用参数,而可以把大部分的经历放在对业务的分析和实现。随着.Net的不断革新,也引入了更多的特性,例如C# 2.0,就增加了匿名方法和迭代器,这些特性让我们的编码效率更高。随着C# 3.0的推出,引入了更多的新特性,包括:隐式类型局部变量、对象初始化器、Lambda表达式、扩展方法、匿名类型。

而这些特性,都为LINQ的推出,构建好了基础。其中一个比较不错的特性,就是扩展方法。扩展方法,顾名思义,就是在类型定义完成之后,再继续为其添加新的方法。这是相当方便的,比如对于一个已经封装好的Assembly来说,我们不用改动Assembly的代码,而通过扩展方法就能实现对其功能的扩展,而且在调用的时候,仅仅通过代码,你几乎判断不出这是扩展方法,还是Assembly本身的方法。

扩展方法在.Net 3.5中的应用也是非常普遍的,如果你仔细观察,就会发现我们常用的Linq to Object中的Where,Select,Average,Sum等方法,以及Linq to SQL中的Where,Select,Average,Sum等方法,其实都是扩展方法,他们分别定义于System.Linq.Enumerable类和System.Linq.Queryable类之中。

就扩展方法本身而言,也存在一些限制之处。对于编译器来说,如果扩展方法和被扩展类型的方法发生冲突的时候,在调用此方法的时候,究竟是调用被扩展类型的方法,还是扩展方法呢?通过一个例子,我们就能发现其中的区别。

<span class="lnum">   1:  </span>  <span class="kwrd">class</span> Program




<span class="lnum">   2:  </span>    {




<span class="lnum">   3:  </span>        <span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)




<span class="lnum">   4:  </span>        {




<span class="lnum">   5:  </span>            <span class="kwrd">new</span> TestClassA().Display(<span class="str">"Test"</span>);




<span class="lnum">   6:  </span>            <span class="kwrd">new</span> TestClassB().Display(<span class="str">"Test"</span>);




<span class="lnum">   7:  </span>            Console.ReadLine();




<span class="lnum">   8:  </span>        }




<span class="lnum">   9:  </span>    }




<span class="lnum">  10:  </span>




<span class="lnum">  11:  </span>    <span class="kwrd">class</span> TestClassA




<span class="lnum">  12:  </span>    {




<span class="lnum">  13:  </span>        <span class="kwrd">public</span> <span class="kwrd">void</span> Display(<span class="kwrd">int</span> b)




<span class="lnum">  14:  </span>        {




<span class="lnum">  15:  </span>            Console.WriteLine(<span class="str">"This is TestClassA.Display() ..."</span>);




<span class="lnum">  16:  </span>        }




<span class="lnum">  17:  </span>    }




<span class="lnum">  18:  </span>




<span class="lnum">  19:  </span>    <span class="kwrd">class</span> TestClassB




<span class="lnum">  20:  </span>    {




<span class="lnum">  21:  </span>        <span class="kwrd">public</span> <span class="kwrd">void</span> Display(<span class="kwrd">string</span> s)




<span class="lnum">  22:  </span>        {




<span class="lnum">  23:  </span>            Console.WriteLine(<span class="str">"This is TestClassB.Display() ..."</span>);




<span class="lnum">  24:  </span>        }




<span class="lnum">  25:  </span>    }




<span class="lnum">  26:  </span>




<span class="lnum">  27:  </span>    <span class="kwrd">static</span> <span class="kwrd">class</span> TestClassExtention




<span class="lnum">  28:  </span>    {




<span class="lnum">  29:  </span>        <span class="kwrd">static</span> <span class="kwrd">public</span> <span class="kwrd">void</span> Display(<span class="kwrd">this</span> <span class="kwrd">object</span> o, <span class="kwrd">string</span> s)




<span class="lnum">  30:  </span>        {




<span class="lnum">  31:  </span>            Console.WriteLine(<span class="str">"This is TestClassExtention.Display() ..."</span>);




<span class="lnum">  32:  </span>        }




<span class="lnum">  33:  </span>    }

程序输出:

ExtentionMethod

可以看出,TestClassA的方法和扩展方法并没有冲突,因为他们的方法签名是不一样的,而TestClassB的方法和扩展方法有冲突,因为他们的都是接受一个string类型的输入参数。从结果可以看到,程序对Display的方法调用,TestClassB本身的Display方法,要“优先”于扩展方法Display被调用。因此,类本身的方法如果满足调用条件,那么这个方法会被优先执行,只有在类当中无法找到同样参数的方法时,扩展方法才有机会被执行。所以,我们可以得出这样的结论:扩展方法的优先级较低,也即扩展方法不会覆盖同名的类本身的方法。

另外,还有一个比较明显的区别,就是扩展方法要远远弱于类本身的方法,比如,在一个类中,类的方法可以访问自己的非公有成员,而扩展方法做不到这一点。

支持原创技术分享,据说打赏我的人,都找到了女朋友!