第十八章 扩展方法
18.1 概述
什么是扩展方法,它可以用来扩展已经定义类型的方法成员。
为了解决每次扩展需要继承的问题,所以C#3.0新添加了扩展方法,为现有的类型添加方法。
【扩展方法特性】
1:扩展方法必须在一个非嵌套,非泛型的静态类中定义
2:至少有一个参数
3:第一个参数必须加上this关键字(第一个参数类型也就是扩展类型,即指方法对这个类型进行扩展)
4:第一个参数不能使用任何其他的修饰符
5:第一个参数类型不能是指针类型
扩展方法的使用,下面的代码演示了如何使用扩展方法:
eg:
// #region >
// /*----------------------------------------------------------------
// // Copyright (C) 2021 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
using System.Collections.Generic;
?
namespace MSN
{? public static class ListExten
{
//定义扩展方法
public static int JSum(this IEnumerable
{
if (source==null)
{
throw (new ArgumentNullException("数组为空"));
}
?
int jsum=0;
bool flag=false;
foreach (int current in source)
{
if (!flag)
{
jsum +=current;
flag=true;
}
else
{
flag=false;
}
}
return jsum;
}
}
class MainClass
{
public static void TestMethod(int input)
{
List
int jsum=ListExten.JSum(source);
Console.WriteLine("数组的奇数之和为" + jsum); source.JSum();
}
?
public static void Main(string[] args) {
MainClass.TestMethod(5);
}
}
}
18.2 扩展方法查找规则
编译器如何发现扩展方法呢?
对于C#3.0编辑器而言,当它看到某个类型的变量在调用方法时候,首先去该对象的实例方法中进行查找,如果没有找到与调用方法同名并且参数一致的实例方法,编译器就会去查找是否存在合适的扩展方法。
编译器会检查所有导入的命名空间和当前的命名空间的扩展方法,并将变量匹配到扩展类型,这里存在一个隐式的类型转换的扩展方法。前面代码之和,List
在VS中,扩展方法前面都有一个向下的箭头标识。
这个是我们人为识别扩展方法的办法,编译器会根据
SystemtimepilerServices.ExtensionAttribute属性来识别扩展方法。如果我们定义的是扩展方法的话,该属性就会被自动绑定到方法之上。
从编译器发现扩展方法的过程来看,方法调用的优先级顺序为:类型的实例方法->当前命名空间下的扩展方法->导入命名空间的扩展方法。
下面我们通过代码来演示编译器发现方法的过程:
// #region >
// /*----------------------------------------------------------------
// // Copyright (C) 2021 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
?
namespace CustomNameSpace
{
using MSN;
?
public static class CustomExtensionClass
{
public static void Print(this Person per)
{
Console.WriteLine("调用的是CustomNameSpace命名空间下扩展方法的输出,姓名为{0}", per.Name);
}
?
public static void Print(this Person per, string s)
{
Console.WriteLine("调用的是当前命名买游戏账号平台空间下的扩展方法输出,姓名为{0},附加字符串{1}", per.Name, s);
}
}
}
?
namespace MSN
{
using CustomNameSpace;
?
public class Person
{
public string Name { get; set; }
}
?
public static class ExtensionClass
{
public static void Print(this Person per)
{
Console.WriteLine("调用的是当前命名空间下的扩展方法输出,姓名为{0}", per.Name);
}
}
?
class MainClass
{
public static void Main(string[] args) {
?
Person p=new Person { Name="zhangsan" };
p.Print();
p.Print("Hello");
}
}
}
注意:
同一个命名空间下的两个类含有扩展类型相同的方法,编译器不知道该如何调用哪个方法,就会出现编译错误。
18.3 空类型调用扩展方法
在C#中,在空引用(null)上调用实例方法会引发NullReferenceException异常的,但在空引用上却可以调用扩展方法,如下代码所示:
// #region >
// /*----------------------------------------------------------------
// // Copyright (C) 2021 极客部落
// // 版权所有。
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// //
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
?
namespace MSN
{
public static class NullExten
{
public static bool IsNull(this object obj)
{
return obj==null;
}
}
?
class MainClass
{
public static void Main(string[] args) {
Console.WriteLine("空类型调用扩展方法演示:");
string s=null;
Console.WriteLine("字符串S为空字符串:{0}", s.IsNull());
}
}
}
?
上述的代码存在缺陷,因为扩展了object,所有继承于object的类型都将具有该扩展方法,这就对其他的类型产生了污染,修改的时候将其改为string即可。之所以不会出现异常,因为编译器只是把空引用s作为参数传入了静态类NullExten,从而调用了静态方法IsNull。
上一篇: javafx学习之数据库操作