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


猜你喜欢
- 前言WebView(网络视图)在Andorid中就是用来显示网页的,下面我们来一起看看它是如何使用的。一、基本使用1.声明权限,WebVie
- SwipeRefresh基于原生的SwipeRefreshLayout 做了封装处理此项目中包括种:1.原生SwipeRefreshLayo
- 本文实例讲述了Java泛型与数据库应用。分享给大家供大家参考,具体如下:一 点睛BaseDao定义了基本的数据库增删查改, 之后可以继承该泛
- 前 言终于来到下篇了,通过上篇,和中篇,我们了解了linq的基本语句,对应linq我们又了解到lambda表达式,静态扩展方法,以及linq
- 本文实例讲述了Android开发之App widget用法。分享给大家供大家参考,具体如下:放在桌面上的控件叫做——App widget,例
- package com.smart.frame.task.autoTask;import java.util.Collection;impo
- 一、什么是深拷贝和浅拷贝对于所有面向对象的语言,复制永远是一个容易引发讨论的题目,C#中也不例外。此类问题在面试中极其容易被问到,我们应该在
- 在谈 JVM 内存区域划分之前,我们先来看一下 Java 程序的具体执行过程,我画了一幅图。Java 源代码文件经过编译器编译后生成字节码文
- 1. 公共字段自动填充1.1 问题分析在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间、修改人等字
- SpringBootWeb开发回顾一下:springboot帮助我们配置了什么,能不能进行修改,能修改哪些,能否扩展?xxxAutoConf
- 一、什么是内存泄漏内存泄漏是指你向系统申请分配内存进行使用(new/malloc),然后系统在堆内存中给这个对象申请一块内存空间,但当我们使
- 二叉树的结构public class TreeNode { int val; &nbs
- 在笔试编程过程中,关于数据的读取如果迷迷糊糊,那后来的编程即使想法很对,实现很好,也是徒劳,于是在这里认真总结了Java Scanner 类
- 简介本文介绍Java的List的正确的删除方法。实例需求:有如下初始数据,将list中的所有数据为"b"的元素删除掉。即
- 目录一 为什么要用锁二 synchronized怎么实现的三 CAS来者何人四synchronized和CAS孰优孰劣轻量级锁重量级锁总结提
- Room在SQLite基础上做了ORM封装,使用起来类似JPA,不需要写太多的sql。导入依赖//roomdef room_version=
- 直接上代码public static class ImageCompress { /// <su
- 前言Android 从 4.0 开始就提供了手机录屏方法,但是需要 root 权限,比较麻烦不容易实现。但是从 5.0 开始,系统提供给了
- 过滤器是Servlet的规范,是基于函数回调的,需要实现javax.servlet.Filter接口,依赖于Tomcat等容器,一般用于过滤
- 本文实例为大家分享了WPF实现背景灯光随鼠标闪动的具体代码,供大家参考,具体内容如下实现效果如下:思路:将容器分割成组合三角形Path,鼠标