C#扩展方法知多少
分三个层面来介绍这个知识点,分别是:.Net内置对象的扩展方法、一般对象的扩展方法、泛型对象的扩展方法。
什么是扩展方法?回答这个问题之前,先看看我们一般情况下方法的调用。类似这样的通用方法你一定写过:
1 static void Main(string[] args) 2 { 3 4 string strRes = "2013-09-08 14:12:10"; 5 var dRes = GetDateTime(strRes); 6 } 7 8 9 //将字符串转换为日期 10 public static DateTime GetDateTime(string strDate) 11 { 12 return Convert.ToDateTime(strDate); 13 } 14 15 //得到非空的字符串 16 public static string GetNotNullStr(string strRes) 17 { 18 if (strRes == null) 19 return string.Empty; 20 else 21 return strRes; 22 }
或者在项目中有一个类似Utils的工具类,里面有多个Helper,例如StringHelper、XmlHelper等等,每个Helper里面有多个static的通用方法,然后调用的时候就是StringHelper.GetNotNullStr("aa");这样。还有一种普通的用法就是new 一个对象,通过对象去调用类里面的非static方法。反正博主刚开始做项目的时候就是这样写的。后来随着工作经验的累积,博主看到了扩展方法的写法,立马就感觉自己原来的写法太Low了。进入正题。
1、.Net内置对象的扩展方法
.Net内部也有很多定义的扩展方法,例如我们Linq常用的Where(x=>x==true)、Select()等等。当你转到定义的时候你很容易看出来:public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)。当然我们也可以给.Net对象新增扩展方法,比如我们要给string对象加一个扩展方法(注意这个方法不能和调用的Main方法放在同一个类中):
1 public static string GetNotNullStr(this string strRes) 2 { 3 if (strRes == null) 4 return string.Empty; 5 else 6 return strRes ; 7 }
然后在Main方法里面调用:
1 static void Main(string[] args) 2 { 3 string strTest = null; 4 var strRes = strTest.GetNotNullStr(); 5 }
简单介绍:public static string GetNotNullStr(this string strRes)其中this string就表示给string对象添加扩展方法。那么在同一个命名空间下面定义的所有的string类型的变量都可以.GetNotNullStr()这样直接调用。strTest.GetNotNullStr();为什么这样调用不用传参数,是因为strTest就是作为参数传入到方法里面的。你可以试试。使用起来就和.Net framework定义的方法一样:
当然除了string,你可以给.Net内置的其他对象加扩展方法,例如给DataGridViewRow的扩展方法:
1 //DataGridViewRow的扩展方法,将当前选中行转换为对应的对象 2 public static T ToObject<T>(this DataGridViewRow item) where T:class 3 { 4 var model = item.DataBoundItem as T; 5 if (model != null) 6 return model; 7 var dr = item.DataBoundItem as System.Data.DataRowView; 8 model = (T)typeof(T).GetConstructor(new System.Type[] { }).Invoke(new object[] { });//反射得到泛型类的实体 9 PropertyInfo[] pro = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public); 10 Type type = model.GetType(); 11 foreach (PropertyInfo propertyInfo in pro) 12 { 13 if (Convert.IsDBNull(dr[propertyInfo.Name])) 14 { 15 continue; 16 } 17 if (!string.IsNullOrEmpty(Convert.ToString(dr[propertyInfo.Name]))) 18 { 19 var propertytype = propertyInfo.PropertyType; 20 } 21 } 22 return model; 23 }
这样看上去就像在扩展.Net Framework。有没有感觉有点高大上~
2、一般对象的扩展方法
和Framework内置对象一样,自定义的对象也可以增加扩展方法。直接上示例代码:
1 public class Person 2 { 3 public string Name { set; get; } 4 public int Age { set; get; } 5 }
1 //Person的扩展方法,根据年龄判断是否是成年人 2 public static bool GetBIsChild(this Person oPerson) 3 { 4 if (oPerson.Age >= 18) 5 return false; 6 else 7 return true; 8 }
Main方法里面调用:
1 var oPerson1 = new Person(); 2 oPerson1.Age = 20; 3 var bIsChild = oPerson1.GetBIsChild();
和string扩展方法类似,就不多做解释了。
3、泛型对象的扩展方法
除了上面两种之外,博主发现其实可以定义一个泛型的扩展方法。那么,是不是所有的类型都可以直接使用这个扩展方法了呢?为了保持程序的严谨,下面的方法可能没有实际意义,当开发中博主觉得可能存在这种场景:
1 public static class DataContractExtensions 2 { 3 //测试方法 4 public static T Test<T>(this T instance) where T : Test2 5 { 6 T Res = default(T); 7 try 8 { 9 Res.AttrTest = instance.AttrTest.Substring(0,2); 10 //其他复杂逻辑... 11 12 13 } 14 catch 15 { } 16 return Res; 17 } 18 19 } 20 21 public class Test2 22 { 23 public string AttrTest { set; get; } 24 }
使用扩展方法有几个值得注意的地方:
(1)扩展方法不能和调用的方法放到同一个类中
(2)第一个参数必须要,并且必须是this,这是扩展方法的标识。如果方法里面还要传入其他参数,可以在后面追加参数
(3)扩展方法所在的类必须是静态类
(4)最好保证扩展方法和调用方法在同一个命名空间下
可能你第一次使用这个会觉得很别扭。你也许会说扩展方法和我以前用的static方法无论从代码实现还是算法效率都差不多嘛,是的!确实差不多,但使用多了之后会发现它确实能帮你省去很多代码。