扩展方法
扩展方法允许我们使用新的方法来扩展现有的类型,而且无需改变现有类型的定义
扩展方法是静态类的一个静态方法,在静态方法里的第一个参数使用this修饰符,第一个参数的类型就是要被扩展的类型。
public static class StringHelper
{
public static bool IsCapitalized(this string s)
{
if (string.IsNullOrEmpty(s))
return false;
return char.IsUpper(s[0]);
}
}
这里的IsCapitalized方法可以被这样调用:
Console.WriteLine(StringHelper.IsCapitalized("Perth"));
Console.WriteLine("Perth".IsCapitalized());
this string 就是拓展了string类型,所以说string.xxx就可以调用IsCapitalized()方法了
C#3.0加入的新特性
扩展方法的实际原理
扩展方法的这种调用方式实际上是这样被翻译的:
arg0.Method(arg1,arg2, ...) // Extension method call
StaticClass.Method(arg0,arg1,arg2,...) //Static method call
接口也可以被扩展
不只是类,接口也可以被扩展(例如Linq,利用Enumerable接口扩展):
public static T First<T>(this IEnumerable<T> sequence)
{
foreach(T element in sequence)
return element;
throw new InvalidOperationException("No elements!");
}
...
Console.WriteLine("Seattle".First()); // S
扩展方法链
扩展方法和实例方法一样,也提供了一种整洁的方式来进行链式调用:
public static class StringHelper
{
public static string Pluralize(this string s){..}
public static string Capitalize(this string s){..}
}
就可以这样调用:
string x ="sausage".Pluralize().Capitalize();
string y = StringHelper.Capitalize(StringHelper.Pluralize("sausage"));
歧义和解析命名空间
只有所在类处于作用范围内的扩展方法才可以被访问,典型的做法是引入命名空间
namespace MyApp
{
using Utils;
Class Test
{
static void
Main()=>Console.WriteLine("Perth".IsCapitalized());
}
}
如果这里不引入Utils命名空间的话,在编译时就会报错的。
歧义和解析 扩展方法 VS 实例方法
兼容的实例方法的优先级总是高于扩展方法
这个例子里,即使你像下面这样调用该Foo方法且传递参数甚至是int类型,而实际执行的方法也是Test的实例方法。
这种情况下,唯一能调用扩展方法的方式就是使用静态调用的语法,也就是Extensions.Foo(…)
歧义和解析 扩展方法 VS 扩展方法
如果两个扩展方法拥有相同的签名,那么扩展方法必须像静态方法那样调用已避免歧义。而如果其中一个扩展方法的参数类型更具体,那么这个方法的优先级就会更高
这种情况下,调用的就是StringHelper上的IsCapitalized方法。
注意:类和结构体被认为比结构更具体。