扩展方法是一种特殊的静态方法,它定义在一个静态类中,但可以在其他类的对象上像调用实例方法那样进行调用。因此,通过扩展方法,我们就可以在不修改一个类型的前提下对一个类型进行功能上的扩充;同时,也可以将一些近似的类型中近似的功能同一实现在一个类中,便于阅读和维护。
另外,扩展方法的引入并非只是简单地为了扩展现有类型,扩展方法的使用还是有一定限制的(这将在稍后谈到)。扩展方法更大的意义在于它为以后将要介绍的查询表达式、查询表达式模式和标准查询运算符的实现奠定了基础,而这些实现正是Linq项目的核心所在。
C#调用扩展方法
扩展方法和一般静态方法的定义方法类似,***的区别是在***个参数的前面要加上关键字this作为修饰符;同时,***个参数的类型也决定了扩展方法可以扩展的类型。
为了介绍扩展方法的定义和使用方法,首先我们定义下面这样一个简单的类作为被扩展对象:
- class SampleClass
- {
- int m_val = 10;
- public int Val { get { return m_val; } set { m_val = value; } }
- public void Func()
- {
- Console.WriteLine("Hey! I’m myself, and my value is {0}.", m_val);
- }
- }
这个类拥有一个公共可读写属性Val,并有一个私有域m_val用于存放这个属性的值。另外,这个类自身还拥有一个公共方法Func,用来在屏幕上显示以行信息,说明该方法被调用了。
然后,我们定义一个静态类型SampleExtensions(这个名字是随意的,只有将扩展方法作为普通的静态方法进行调用时才会用到这个名字),其中定义一个用于扩充SampleClass类型的扩展方法ExFunc:
- static class SampleExtensions
- {
- public static void ExFunc(this SampleClass s)
- {
- Console.WriteLine("Aha! I’m going to modify the SampleClass!");
- s.Val = 20;
- s.Func();
- }
- }
注意这个方法的***个参数(也是仅有的一个参数)的类型前面多了一个修饰符this,这表明该方法用来扩展SampleClass类型,也就是说可以在SampleClass类型的对象上像调用实例方法那样调用ExFunc方法。该方法首先告诉用户它正在被调用,然后修改SampleClass类型的对象的属性,并调用它的实例方法。
接下来,我们在Main方法中创建SampleClass类型的一个实例,并尝试调用其实例方法和上面定义的扩展方法:
- SampleClass s = new SampleClass();
- Console.WriteLine("Calling the instance method:");
- s.Func();
- Console.WriteLine();
- Console.WriteLine("Calling the extension method:");
- s.ExFunc();
当然,由于扩展方法只是静态方法的一种特例,我们同样可以像用调用一般静态方法那样来C#调用扩展方法。
这会得到完全一样的结果。而且事实上,编译器也正是将C#调用扩展方法翻译为了一般形式的静态方法调用,然后才进行进一步的编译。
扩展方法不仅能扩展同一个程序集中的类型,同时也能扩展不同程序集甚至是已经发布了的程序集中的类型。下面我们就在SampleExtensions中再添加一个扩展方法,用来扩展.net Framework的内建类型String(这个例子摘录自C# 3.0语言规范,版权归微软公司所有。)
- public static int ToInt32(this string s)
- {
- return Int32.Parse(s);
- }
- //然后,我们就可以象下面这样方便地将一个字符串转换为一个整型了:
- string sval = "20";
- Console.WriteLine("String ’20’ means integer: {0}.", sval.ToInt32());
- //尝试运行这段代码,会得到如下结果:
- String ’20’ means integer: 20.
简单地浏览一下.NET Framework的文档就会发现,System.String类型中的确没有定义ToInt32方法,这说明我们的扩展方法在.NET Framework内建类型上仍然有效。
【编辑推荐】