以前总听说扩展方法扩展方法,只是听说是C#3.0后出来的新玩意,也仅仅是知道Linq中用到好多的扩展方法,但是他究竟是个什么东东,怎么用它,用它的好处是什么,总是模模糊糊,那么我们今天就尝试揭开它神秘的面纱。
我们现在看到每个方法都和声明它的类关联,但是C#3.0的扩展方法的特性扩展了这个边界,允许编写和声明它的类之外的类关联的方法。想要知道如何利用这个特征,我们先看一个例子:
class MyData{
double D1,D2,D3;public MyData(double d1,double d2,double d3){
D1
=d1;D2=d2;D3=d3;}
public double Sum(){
return D1+D2+D3;}
}
这是一个非常简单而且功能有限,但假设它含有另外一个方法会更有用,该方法返回三个数据的平均值.那么我们有几种方法可以实现这个增加的功能.
如果我们不能访问代码,或该类是密封的,或有其它设计原因使这些方法不能工作,那么我们不得不在另外一个类中使用该类的公有可用成员编写一个方法.
例如,我们可以编写一个下面代码中这样的类:
static class ExtendMyData{
public static double Average(MyData md){
return md.Sum()/3;}
}
上面代码包含一个名称为ExtendMyData的静态类,它包含一个名称为Avarage的静态方法,该方法实现了新增的功能.
调用代码:
public class MyClass{
public static void Main(){
MyData md
=new MyData(1,2,3);Console.WriteLine(
"Average:{0}",ExtendMyData.Average(md));}
}
这段代码输出: Average:2
尽管这是非常好的解决方案,但如果能在类的实例自身调用该方法,而不是创建一个作用于它的类的实例,它将会更优雅。下面两行代码阐明了它们的区别。第一行使用刚展示的方法:在另一个类的实例上调用静态方法。第二行展示了我们愿意使用的形式:在对象自身上调用实例犯非法。
ExtendMyData.Average(md);//在一个类的实例上调用静态方法md.Average(); //在对象自身上调用实例方法
扩展方法允许你使用第二种形式,即使第一种形式可能是编写这种调用的正确方法。通过对方法Average的声明做一个小小的改动,就可以实现实例调用方式。需要修改的是在参数生命中的类型名称前增加关键字this,如下面所示。把this关键字加到静态类的静态方法的第一个参数上,把该方法从ExtendMyData的正规方法改变为类MyData的扩展方法。现在两种调用方式都可以使用:
static class ExtendMyData{
public static double Average(this MyData md){
}
}
扩展方法重要的需求如下:
- 声明扩展方法的类必须声明为static.
- 扩展方法本身必须声明为static.
- 扩展方法必须包含关键字this作为它的第一个参数类型,并在后面跟着它所扩展类的名称。
另外需要注意的是:C#只支持扩展方法,不支持扩展属性、扩展事件等。
下面代码展示了展示了一个完整的程序,注意方法Average完全如同它是MyData的实例成员那样被调用!
using System;using System.Collections.Generic;public class MyClass{
public static void Main(){
MyData md
=new MyData(1,2,3);Console.WriteLine(
"Sum:{0}",md.Sum());Console.WriteLine(
"Average:{0}",md.Average());}
}
class MyData{
double D1,D2,D3;public MyData(double d1,double d2,double d3){
D1
=d1;D2=d2;D3=d3;}
public double Sum(){
return D1+D2+D3;}
}
static class ExtendMyData{
public static double Average(this MyData md){
return md.Sum()/3;}
}
为了方便大家理解,我又增加了一个例子。分别为string 和集合做扩展方法:
using System;using System.Collections.Generic;using System.Collections;using Extend;//扩展方法的命名空间namespace Mytest{
public class MyClass{
public static void Main(){
string str = "{0}先生。".With("幕三少");Console.WriteLine(
"您好!:"+str);//调用集合的扩展方法str.ShowItems<char>();
Console.Read();
}
}
}
namespace Extend{
static class ExtendMyData{
public static string With(this string content,params string[] args){
return string.Format(content,args);}
//为集合做扩展方法public static void ShowItems<T>(this IEnumerable<T> items)
{
foreach (var item in items)
{
Console.WriteLine(item);
}
}
}
}