概念
- 扩展方法是一种特殊类型的静态方法。对于一个C#类型,如类(包括密封类)、值类型、接口等,扩展方法可以在不改变类型源码的前提下,为它的实例提供新的成员。
如何定义
- 创建扩展方法很简单,有以下步骤
- 创建一个静态类;
- 在其中创建一个静态方法;
- 为这个静态方法添加至少一个参数,并在第一个参数前加上this关键字,这个关键字会告诉编译器当前方法是一个扩展方法。而这个方法将成为第一个参数所属类型的新成员。
- 注意:只有在引用扩展方法所在的静态类的命名空间后,才能使用扩展方法,否则,直接调用会编译失败。在上例中,使用该扩展方法要引用TLA.Infrastructure.Extensions命名空间。
> 如何使用
- 扩展方法可以用在以下几种场合:
- 要为某个类型扩展功能,但没有其源码,比如某个款哪个家或第三方库中的一个类;例如,想要获取一个列表中的所有的奇数项,就可以为IList<T>接口增加一个扩展方法,这里的IList<T>接口本身是.NET框架中的接口。
public static class IListExtentions {
public static IEnumerable<T> OddItems<T>(this IEnumerable<T> list)
{
if(list==null)
{
throw new ArgumentNullException(nameof(list));
}
for (int i=0;i<list.Count();i++>)
{
if(i%2==0)
{
yield return list.ElementAt(i);
}
}
}
}
- 即使可以访问原有类型的源码,也可以使用扩展方法为它添加辅助功能;
public interface ILog {
void Log(string message,LogLevel logLevel);
} public static class ILogExtensions {
public static void LogDebug(this ILog logger,string message)
{
if(true)
{
logger?.Log($"{message}",LogLevel.Debug);
}
}
} ```
注意事项
- 扩展方法的本质是为原有类型提供辅助功能,因此,在创建时,要确保它具有实际意义,且遵循单一职责原则;也即,不能过度使用扩展方法并且它能够完成一个具体、完整的功能;
- 扩展方法本身具有通用性,因此,它里面应避免特定的业务数据类型及其相关逻辑;
- 如果为接口增加扩展方法,扩展方法的命名空间可以与接口一致;否则,应尽量避免与原类型写在同一个命名空间下,这样会“污染”原类型。建议做法是为扩展方法所在的类设定一个单独的命名空间,如:..Extentions。不过,这样做也有缺点;在操作原有类型的实例时,如果不引用扩展方法所在的命名空间,那么,它就不容易被发现,而解决这个问题的方法是,尽量将扩展方法文档化,并告诉项目组的其他开发人员
- 为接口增加扩展方法后,则所有实现此接口的类都会包含该扩展方法;
- 在扩展方法中,要对第一个参数进行非空检查,如果为空,应抛出ArgumentNullException异常。
总结
- 声明扩展方法的必须条件
- 方法必须定义在顶级的静态中,并且该静态类必须直接处在命名空间下而且不能为泛型类(即方法必须放在非嵌套、非泛型的静态中)
- 方法必须是静态的并且第一个参数用this关键字修饰,这个参数被叫做【参数实例】
- 方法的访问修饰符必须是public
- 至少有一个参数
- 不能有其他参数修饰第一个参数(如ref,out)
- 第一个参数的类型不能是指针类型
注意事项
扩展方法相关原理