扩展方法

扩展方法允许我们使用新的方法来扩展现有的类型,而且无需改变现有类型的定义
扩展方法是静态类的一个静态方法,在静态方法里的第一个参数使用this修饰符,第一个参数的类型就是要被扩展的类型。

  1. public static class StringHelper
  2. {
  3. public static bool IsCapitalized(this string s)
  4. {
  5. if (string.IsNullOrEmpty(s))
  6. return false;
  7. return char.IsUpper(s[0]);
  8. }
  9. }

这里的IsCapitalized方法可以被这样调用:

  1. Console.WriteLine(StringHelper.IsCapitalized("Perth"));
  2. Console.WriteLine("Perth".IsCapitalized());

this string 就是拓展了string类型,所以说string.xxx就可以调用IsCapitalized()方法了
C#3.0加入的新特性

扩展方法的实际原理

扩展方法的这种调用方式实际上是这样被翻译的:

  1. arg0.Method(arg1,arg2, ...) // Extension method call
  2. StaticClass.Method(arg0,arg1,arg2,...) //Static method call

接口也可以被扩展

不只是类,接口也可以被扩展(例如Linq,利用Enumerable接口扩展):

  1. public static T First<T>(this IEnumerable<T> sequence)
  2. {
  3. foreach(T element in sequence)
  4. return element;
  5. throw new InvalidOperationException("No elements!");
  6. }
  7. ...
  8. Console.WriteLine("Seattle".First()); // S

扩展方法链

扩展方法和实例方法一样,也提供了一种整洁的方式来进行链式调用:

  1. public static class StringHelper
  2. {
  3. public static string Pluralize(this string s){..}
  4. public static string Capitalize(this string s){..}
  5. }

就可以这样调用:

  1. string x ="sausage".Pluralize().Capitalize();
  2. string y = StringHelper.Capitalize(StringHelper.Pluralize("sausage"));

歧义和解析命名空间

只有所在类处于作用范围内的扩展方法才可以被访问,典型的做法是引入命名空间

  1. namespace MyApp
  2. {
  3. using Utils;
  4. Class Test
  5. {
  6. static void
  7. Main()=>Console.WriteLine("Perth".IsCapitalized());
  8. }
  9. }

如果这里不引入Utils命名空间的话,在编译时就会报错的。

歧义和解析 扩展方法 VS 实例方法

兼容的实例方法的优先级总是高于扩展方法
未命名图片.png
这个例子里,即使你像下面这样调用该Foo方法且传递参数甚至是int类型,而实际执行的方法也是Test的实例方法。
这种情况下,唯一能调用扩展方法的方式就是使用静态调用的语法,也就是Extensions.Foo(…)

歧义和解析 扩展方法 VS 扩展方法

如果两个扩展方法拥有相同的签名,那么扩展方法必须像静态方法那样调用已避免歧义。而如果其中一个扩展方法的参数类型更具体,那么这个方法的优先级就会更高
未命名图片.png
未命名图片.png

这种情况下,调用的就是StringHelper上的IsCapitalized方法。
注意:类和结构体被认为比结构更具体。