在我们的编程生涯中我们要使用很多很多类库这些类库有的是我们自己开发的我们有她的代码有的是第三方发布的我们不仅没有他们的代码连看的机会都没有
作程序员我们每天都要和BCL(Base Class Linbrary)打交道无疑BCL做为一个年轻的框架类库她是成功的但是还有一些时候我们还是得写一些Helper方法来扩展类库由于我们不能修改类库的源代码我们只有写一个个的静态类虽然在使用上也算方便但作为追求完美的程序员来说总有些不雅现在我就碰到这样的事情前两天奉命写一个从XML文件加载Chart图的设置的方法从XML加载数据绑定到对象上这肯定是反射的用武之地了我经常需要写一些根据对象属性名字来判断这个对象是否有这个属性或者根据属性名获取该属性的值还是按照平常一样我很快写了一个PropertyHelper里面有两个静态方法HasPropertyGetValueByName
PropertyHelperHasProperty(point X)如此的调用也还过得去不过在C# 微软为我们提供了扩展方法现在我们可以直接这样调用了pointHasProperty(X);看看我是如何实现这个扩展方法的?
publicstaticclassPropertyExtension
{
publicstaticobjectGetValueByName(thisobjectselfstringpropertyName)
{
if(self==null)
{
returnself;
}
Typet=selfGetType();
PropertyInfop=tGetProperty(propertyName);
returnpGetValue(selfnull);
}
}
我给object类型添加了一个扩展方法里所有的类都继承自object那所有的类都默认的拥有这个方法了真方便呵呵
注意到和普通的静态方法有何差别?在这个方法的第一个参数前面多了一个this关键字
扩展方法
方法所在的类必须是静态的
方法也必须是静态的
方法的第一个参数必须是你要扩展的那个类型比如你要给int扩展一个方法那么第一个参数就必须是int
在第一个参数前面还需要有一个this关键字
按照上面的步骤写你就得到了一个扩展方法你可以像调用这个类的原生方法那样去调用它
stringstr=abc;
objectlen=strGetValueByName(Length);
好像string类型现在有了GetValueByName这个方法一样但实际上string并没有这样一个方法那这又是为什么呢?是我们可爱的编译器在其中做了手脚为了避开编译器的干扰我们来直接欣赏MSIL代码
L_:ldstrLength
L_d:callobjectTestLambdaPropertyExtension::GetValueByName(objectstring)
从MSIL中我们可以看出这段代码编译后和调用静态方法没有任何的差别(从call指令来看这是在调用一个静态方法)
从这里可以知道扩展方法即可以使用实例调用的方式也可以直接使用静态类调用的方式
strGetValueByName(Length);
PropertyExtensionGetValueByName(strLength);
下面将对扩展方法做一些细节的介绍
Visual Studio 对扩展方法有智能感知的支持如下图
在方法的图标上有一个与其他的都不相同他的突变下面还带有一个蓝色的向下的箭头这就表明这个方法是一个扩展方法
下面是对编写扩展方法要注意的几个原则(当然仁者见仁智者见智这也是一家之言)
扩展方法有就近原则也就是如果在你的程序里有两个一模一样的扩展方法一个和你的使用类是处于同一命名空间里另外一个处于别的命名空间里这个时候会优先使用同一命名空间里的扩展方法也就是说血缘关系越近越被青睐
很多人看到扩展方法也许眼里冒出金光以后在设计的时候不管三七二十一反正可以扩展还有一些人会对类任意扩展将以前一些作为Helper的方法统统使用扩展方法代替注意的是扩展方法有污染性所以我觉得在扩展的时候还是想想是不是值得这样扩展
在扩展的时候也不要对比较高层的类进行扩展像我上面对object的扩展我觉得就是不可取的object是所有类的基类一经扩展所有的类都被污染了