定义
用来扩展已定义类型中的方法成员
在扩展方法之前,扩展一个方法需要使用继承来扩展现有类来扩展现有类型,并且值类型和密封类型(sealed)是不能被继承的定义规则
扩展方法的定义规则
- 扩展方法必须在一个非嵌套、非泛型的静态类(即在类中定义类)中进行定义
- 至少有一个参数
- 第一个参数必须加上this关键字作为前缀(第一个参数类型也被称为扩展类型,即指方法对这个类型进行扩展)
- 第一个参数不能使用任何其他的修饰符(如ref out等)
- 第一个参数的类型不能是指针类型
代码示例:
using system;
using system.Collection.Generic;
//扩展方法必须定义在非泛型静态类中
public static class ListExten
{
//定义扩展方法
public static int JSum(this IEnumerable source)
if(source==null)
{
throw new ArgumentNukkException("输入数组为空");
}
int jsum=0;
bool flag=false;
foreach(int current in source)
{
if(!flag)
{
jsum+=current;
flag=true;
}
else
{
flag=false;
}
}
return jsum;
}
使用
代码示例:
using system;
using system.Collection.Generic;
class program
{
//调用扩展方法
static void Main(string[] args)
{
Listsource=new List{1,2,3,4,5,6};
//第一种调用方式
int jsum=ListExten.JSum(source);
//第二种调用方式
int jsum1=source.JSum();
Console.WriteLine("数组之和为:"+jsum);
Console.WriteLine("数组之和为:"+jsum1);
Console.Readline;
}
}
编译器发现扩展方法
当编译器看到类型的变量在调用方法时,会首先在对象的实例方法中查找,如果没有找到就查找是否存在合适的扩展方法,此时编译器会检查所有导入的命名空间和当前命名空间中的扩展方法,并将变量类型匹配到扩展类型,这里存在一个隐式转换的扩展方法(子类到父类的转换可以通过隐式转换来完成) 扩展方法在智能提示中都有一个向下的箭头来进行标识,编译器则通过System.Runtime.CompilerServices.ExtensionAttribute属性来识别扩展方法
当编译器看到某个类型的变量在调用方法时 查找顺序:
- 对象的实例方法
- 当前命名空间下的扩展方法
- 导入命名空间下的扩展方法
注意事项
- 如果扩展的类型中定义了无参数的实例方法名(如:Print),则在扩展方法在定义该名称的扩展方法(Print),则实例在后续调用时只能提示不会出现该扩展方法
- 如果在同一个命名空间下的两个类中含有扩展类型相同的方法,编译器就不知道该调用哪个方法了就会出现编译错误
空引用也可以调用扩展方法
空引用null上调用实例方法会引发NullReferenceException异常,但是在空引用上却可以调用扩展方法
public static class NullExte
{
//第一种扩展 此种扩展方法会对其他子类产生污染
public static bool IsNull(this object obj)
{
return obj==null;
}
//第二种扩展方法
public static bool isNull(this string str)
{
return str==null;
}
}