前沿:
扩展方法使你能够向现有类型“添加“方法,而无需创建新的派生类型、重新编译或以其它方式修改原始类型。扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。
正文:
为了理解扩展方法,最佳的办法就是看代码,假如我们要定义一个下面这样的IndexOf方法:
public static class StrignBuilderExtensions { public static int IndexOf(StringBuilder sb, char value) { for (int i = 0; i < sb.Length; i++) { if (sb[i] == value) return i; } return -1; } }
定义哈皮这个方法后,可以在代码中使用它,如下所示:
StringBuilder sb = new StringBuilder("Hello,my name is"); int index = StrignBuilderExtensions.IndexOf(sb.Replace(‘,‘, ‘!‘), ‘!‘);
上述代码看起来没有什么问题,但从程序员的角度看不是很理想。第一个问题是,要获取一个StringBuilder中的某个字符的做索引,必须要知道StrignBuilderExtensions存在,第二个问题是,代码没有反映在StringBuilder对象上执行的操作的顺序,使码难写、读和维护。我们希望先调用Replace,再在调用IndexOf,但从左向右读最后一行代码,先看到的是IndexOf,然后才看到Replace。当然,可以下面这样写,事代码的行为看起来容易理解。
sb.Replace(‘,‘, ‘!‘); int index = StrignBuilderExtensions.IndexOf(sb, ‘!‘);
但是这两个版本都会影响我们对代码行为的理解。StrignBuilderExtensions显得“小题大做“,造成我们无法专注于当前要执行的操作,如果StringBuilder类内部定义了IndexOf方法,就可以将上述代码重写为:
int i = sb.Replace(‘,‘, ‘!‘).IndexOf(‘!‘);
有了这个例子做铺垫,就很容易理解C#扩展方法所做的事情了。他允许你定义一个静态方法,并且用实例方法的语法调用他。换言之,现在可以定义自己的IndexOf方法。同时避免出现上述问题,为了将IndexOf转变成扩展方法,只需在第一个参数前加this关键字
public static class StrignBuilderExtensions { public static int IndexOf(this StringBuilder sb, char value) { for (int i = 0; i < sb.Length; i++) { if (sb[i] == value) return i; } return -1; } }
现在,当编译器看到如下代码:
int index=sb.IndexOf(‘x‘);
它首先检查StringBuilder类或者他的任何基类是否提供了获取单个Char参数,名为IndexOf的实例方法。如果存在这样一个实例方法,编译器会生成IL代码来调用它。
如果没有发现匹配的实例方法,则继续检查是否有任何静态类定义了一个名为IndexOf的静态方法,她的第一个参数是和当前调用方法的那个表达式的类型匹配的一个类型,而且这个类型必须使用this关键字来标示.