扩展方法可以理解为现有的类型(现有类型可以为自定义的类型和.Net 类库中的类型)扩展(添加)应该附加到该类型中的方法。
在没有扩展方法之前,如果我们想为一个已有类型自定义自己逻辑的方法时,我们必须自定义一个新的类型来继承已有类型的方式来添加方法
扩展方法必须具备下面的规则:
- 它必须在一个非嵌套、非泛型的静态类中
- 它至少要有一个参数
- 第一个参数必须加上this关键字作为前缀(第一个参数类型也称为扩展类型,即指方法对这个类型进行扩展)
- 第一个参数不能用其他任何修饰符(如不能使用ref out等修饰符)
- 第一个参数的类型不能是指针类型
演示代码:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CustomNamesapce { using EventDemo; public static class CustomExtensionClass { /// <summary> /// 扩展方法定义 /// </summary> /// <param name="per"></param> public static void Print(this Person per) { Console.WriteLine("调用的是不同命名空间下扩展方法输出,姓名为: {0}", per.Name); } /// <summary> /// 扩展方法定义 /// </summary> /// <param name="per"></param> public static void Print(this Person per, string s) { Console.WriteLine("调用的是不同命名空间下扩展方法输出,姓名为: {0}, 附加字符串为{1}", per.Name, s); } } }

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EventDemo { // 要使用不同命名空间的扩展方法首先要添加该命名空间的引用 using CustomNamesapce; class Program { static void Main(string[] args) { Person p = new Person { Name = "Learning hard" }; // 当类型中包含了实例方法时,VS中的智能提示就只会列出实例方法,而不会列出扩展方法 // 当把实例方法注释掉之后,VS的智能提示中才会列出扩展方法,此时编译器在Person类型中找不到实例方法 // 所以首先从当前命名空间下查找是否有该名字的扩展方法,如果找到不会去其他命名空间中查找了 // 如果在当前命名空间中没有找到,则会到导入的命名空间中再进行查找 p.Print(); p.Print("Hello"); Console.Read(); } } // 自定义类型 public class Person { public string Name { get; set; } // 当类型中的实例方法 ////public void Print() ////{ //// Console.WriteLine("调用实例方法输出,姓名为: {0}", Name); ////} } // 当前命名空间下的扩展方法定义 public static class Extensionclass { /// <summary> /// 扩展方法定义 /// </summary> /// <param name="per"></param> public static void Print(this Person per) { Console.WriteLine("调用的是同一命名空间下的扩展方法输出,姓名为: {0}", per.Name); } } }
大家都知道在C#中,在空引用上调用实例方法是会引发NullReferenceException异常的,但是可以在空引用上调用扩展方法,下面看一段演示代码:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EventDemo { namespace ExtensionDefine { /// <summary> /// 扩展方法定义 /// </summary> public static class NullExten { // 此时扩展的类型为object,这里我是故意用object类型的 // 如果是为了演示,当我们为一个类型定义扩展方法时,应尽量扩展具体类型,如果扩展其基类的话 // 则所有继承于基类的类型都将具有该扩展方法,这样对其他类型来说就进行了“污染 // 子所以形成了污染,是因为我们定义的扩展方法的意图本来只想扩展某个子类。 // 其实下面这个方法我的意图只是想扩展string类型的,所以更好的定义方法如下: //public static bool isNull(this string str) //{ // return str == null; //} // 不规范定义扩展方法的方式 public static bool IsNull(this object obj) { return obj == null; } } } }

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EventDemo { // 必须引入扩展方法定义的命名空间 using ExtensionDefine; class Program { static void Main(string[] args) { Console.WriteLine("空引用上调用扩展方法演示:"); string s = null; // 在该程序中要使用扩展方法必须通过using来引用 // 在空引用上调用扩展方法不会发生NullReferenceException异常 // 之所以不会出现异常,是因为在空引用上调用扩展方法,对于编译器而言只是把空引用s当成参数传入静态方法中而已 // 对于编译器来说,s.IsNull()的调用等效于下面的代码 //Console.WriteLine("字符串S为空字符串:{0}", NullExten.IsNull(s)); Console.WriteLine("字符串S为空字符串:{0}", s.IsNull()); Console.ReadKey(); } } }