本文主要以下面几个方面来详细讲解扩展方法:在C#3.0之前没有扩展方法的状态(或者你不会使用不知道扩展方法的时候)、扩展方法的语法及怎么使用、怎么正确的使用扩展方法;
一、首先说一下在C#3.0之前没有扩展方法的状态(或者你不会使用不知道扩展方法的时候)
1、大家在项目中肯定遇到类似这样的需求且项目很多地方都会用到:1.需要对一个对象进行可空判断;2、对一个集合或者对象进行序列化;3、时间格式转换;4、List与DataTabel之前转换等等。
我想在没有扩展方法之前大家基本上都是做一个类似common的静态公共静态类,写一些静态方法供项目各个调用调用 如:
public static class Common { /// <summary> /// 判断是否为Null或者空 /// </summary> /// <param name="obj">对象</param> /// <returns></returns> public static bool IsNullOrEmpty( object obj) { if (obj == null) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } }
其他类调用公共方法
static void Main(string[] args) { string str = "lxsh"; Common.IsNullOrEmpty(str); }
通过这样也能完成上面所说的几个需求,但是让人感觉上端一直要显示依赖Common这个静态类,项目中就会大量充斥着这样的代码,看起来不那么简洁,而且也不利于后期的链式语法编程;
2、有时也会遇到这样的情况:你想对某个类型加一些行为(方法),但你不能改变该类型的本身,因为是别人的代码,遇到这样情况你可能会增加一个继承接口,或者一个抽象类,或者通过代理模式封装一次,这样显然能达到目的但都很麻烦;
以上解决办法都是在没有使用扩展方法之前的解决方案,当你学会了扩展方法,你可能会有更好的选择;
二、 接下来我们来说一下扩展方法的语法及使用
1、扩展方法必须具备以下几个特征:
- 必须是在非嵌套的、非泛型的静态类中
- 必须在静态类中的静态方法
- 至少要有一个参数
- 第一个参数的前缀必须加this关键字且不能有任何修饰符(如:ref,out)且参数类型不能为指针
例如:
public static partial class Extensions { public static string ObjectToJSON(this object obj) { return JsonConvert.SerializeObject(obj, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }); } /// <summary> /// 判断是否为Null或者空 /// </summary> /// <param name="obj">对象</param> /// <returns></returns> public static bool IsNullOrEmpty(this object obj) { if (obj == null) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } }
2、怎么使用扩展方法:
先引用扩展方法静态类所在的命名空间,引用完成后,在调用的时候它在你对应类型实例上面有”智能感知“提示
3、扩展方法是怎么被发现调用的
如果在using命令,将扩展方法引用到代码中,扩展方法可以像类一下不加限制地在代码中使用。如果编译器认为一个表达试好像要使用一个实例方法,但没有找到与这个方法调用兼容的实例方法,就会查找一个合适的扩展方法。它会检查导入的所有命名空间和当前命名空间中所有的扩展方法,并匹配那些从表达式类型到扩展类型存在隐式转换的扩展方法;
简单一句话讲:编译器首先会查看这类型(包括父类)有没有对应的该实例方法,如果有该实例方法他就不会执行扩展方法,如果没有它就会找对应的扩展方法执行;
假如有一个 student类,它有一个实例方法say,再给他加一个扩展方法say
public class Student { public void Say() { Console.WriteLine("我是实例方法"); } } public static class Extensions { public static void Say(this Student student) { Console.WriteLine("我是扩展方法"); } }
static void Main(string[] args) { Student student = new Student(); student.Say(); Console.ReadKey(); }
执行结果为:
还有一种情况,对子类和父类同时加了一个一样的扩展方法,且都引用了他们名词空间,优先调用子类的扩展方法(同样适用于接口父子关系)
public class Pers