以下是常规获取现在时间的一个方法。当有一天这个"yyyy-MM-dd"格式,有个需求需要在一千个方法中实现,你确定要写上一千次?不会吧!于是得想办法格式化一次便能达到目的。
1 /// <summary> 2 /// 静态方法,便于在Main函数中调用. 3 /// </summary> 4 static void ExtMethod() 5 { 6 DateTime now = DateTime.Now; 7 // 时间格式 年-月-日 8 string yyyymmddFmt = now.ToString("yyyy-MM-dd"); 9 Console.WriteLine(yyyymmddFmt); 10 }
你会想到写一个静态类,静态方法。于是马不停蹄的新建类··· 新建方法···
1 /// <summary> 2 /// 静态类,静态方法 3 /// </summary> 4 public static class ExtMehtodHelp 5 { 6 public static string FmtYYYYMMDD(DateTime date) 7 { 8 // 返回时间 9 return date.ToString("yyyy-MM-dd"); 10 } 11 }
然后在ExtMethod()方法中,便可以通过静态类点出静态方法。然后你在这一千个方法中都调用了这个静态方法。
1 /// <summary> 2 /// 静态方法,便于在Main函数中调用. 3 /// </summary> 4 static void ExtMethod() 5 { 6 DateTime now = DateTime.Now; 7 // 时间格式 年-月-日 8 string yyyymmddFmt = now.ToString("yyyy-MM-dd"); 9 // 调用静态类中的静态方法 10 string fmt01 = ExtMehtodHelp.FmtYYYYMMDD(now); 11 12 Console.WriteLine(fmt01); 13 }
静态类点出静态方法,确是无可厚非的。
如果有一种更简单的方法通过 DateTime 的 now 变量直接点出方法 FmtYYYYMMDD 的话。那多好哇,类名都用不着记了!
也可以认为 now 是一个实例,想要在实例上点出方法,那么必须是实例方法。而DateTime是微软封装好的代码,我们无法改动,所以
无法往类里面添加方法。然而现在又有这么一个需求,所以提供了一种方法叫做扩展方法。
1 /// <summary> 2 /// 扩展方法的必要条件 3 /// 1、此方法必须是一个静态方法 4 /// 2、此方法必须放到静态类中 5 /// 3、方法的第一个参数要以this开头,后面跟着此扩展方法所在的类型参数 6 /// </summary> 7 public static class ExtMehtodHelp 8 { 9 // 谁点出此方法就要在其类型前加this 10 // DateTime有个形参,表示此方法扩展至DateTime。date代表当前变量now 11 public static string FmtYYYYMMDD(this DateTime date) 12 { 13 return date.ToString("yyyy-MM-dd"); 14 } 15 }
于是在调用的时候就可以直接通过 now.FmtYYYYMMDD 来获取。在now点方法的时候,FmtYYYYMMDD方法前面是有一个向下的箭头,表示此为扩展方法。
1 /// <summary> 2 /// 静态方法,便于在Main函数中调用. 3 /// </summary> 4 static void ExtMethod() 5 { 6 DateTime now = DateTime.Now; 7 // 普通形式 时间格式 年-月-日 8 string yyyymmddFmt = now.ToString("yyyy-MM-dd"); 9 // 调用静态类中的静态方法 10 string yyyymmddFmt01 = ExtMehtodHelp.FmtYYYYMMDD(now); 11 // 调用扩展方法 12 string yyyymmddFmt02 = now.FmtYYYYMMDD(); 13 14 Console.WriteLine(yyyymmddFmt02); 15 }
给扩展方法加多一个参数,这便是扩展方法的真正参数
1 /// <summary> 2 /// 扩展方法的另外一个参数,才是他的真正参数 3 /// </summary> 4 public static class ExtMehtodHelp 5 { 6 public static string FmtYYYYMMDD(this DateTime date,string str) 7 { 8 return date.ToString("yyyy-MM-dd"); 9 } 10 11 }
1 /// <summary> 2 /// 静态方法,便于在Main函数中调用. 3 /// </summary> 4 static void ExtMethod() 5 { 6 DateTime now = DateTime.Now; 7 // 普通形式 时间格式 年-月-日 8 string yyyymmddFmt = now.ToString("yyyy-MM-dd"); 9 // 调用静态类中的静态方法 10 //string yyyymmddFmt01 = ExtMehtodHelp.FmtYYYYMMDD(now); 11 // 调用扩展方法 12 // 这才是扩展方法的真正参数 13 string yyyymmddFmt02 = now.FmtYYYYMMDD("Hello"); 14 15 Console.WriteLine(yyyymmddFmt02); 16 }
总结:通过反编译工具可看出,扩展方法其本质是静态方法。编译器认为一个表达方式是要使用一个实例方法,但是没有找到,就会检查导入的命名空间和当前命名空间里所有的扩展方法,并匹配适合的方法
.method private hidebysig static void ExtMethod() cil managed { .maxstack 2 .locals init ( [0] valuetype [mscorlib]System.DateTime time, [1] string str) L_0000: nop L_0001: call valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now() L_0006: stloc.0 L_0007: ldloc.0 L_0008: ldstr "Hello" L_000d: call string D03_01新语法.ExtMehtodHelp::FmtYYYYMMDD(valuetype [mscorlib]System.DateTime, string) L_0012: stloc.1 L_0013: ldloc.1 L_0014: call void [mscorlib]System.Console::WriteLine(string) L_0019: nop L_001a: ret }
扩展方法的必要条件
1、此方法必须是一个静态方法
2、此方法必须放到静态类中
3、方法的第一个参数要以this开头,后面跟着此扩展方法所在的类型参数
特点:(这里没有演示)
1、扩展方法与实例方法可以构造成重载
2、如果扩展方法的名称和参数与实例方法相同,则实例方法的优先级高于扩展方法来调用
3、扩展在父接口或父类上的扩展方法,在子类的实例中也可以调用