.NET 3.5提供的扩展方法特性,可以在不修改原类型代码的情况下扩展它的功能。下面分享的这些扩展方法大部分来自于Code Project或是Stackoverflow,.NET为此还有一个专门提供扩展方法的网站(extensionMethod)。
涵盖类型转换,字符串处理,时间转化,集合操作等多个方面的扩展。
这个需求来源于界面中使用BackgroundWorker,为了给DoWork传递多个参数,又不想定义一个类型来完成,于是我会用到TolerantCast方法。参考如下的代码:
//创建匿名类型 var parm = new { Bucket = bucket, AuxiliaryAccIsCheck = chbAuxiliaryAcc.Checked, AllAccountIsCheck = chbAllAccount.Checked }; backgroundWorker.RunWorkerAsync(parm); private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { //解析转换匿名类型 var parm = e.Argument.TolerantCast(new { Bucket = new RelationPredicateBucket(), AuxiliaryAccIsCheck = false, AllAccountIsCheck = false });
这个方法的定义很简单但也很实用,它的使用方法如下:
var buttons = GetListOfButtons() as IEnumerable<Button>; buttons.ForEach(b => b.Click());
扩展方法的源代码定义只有一行,源代码如下:
public static void ForEach<T>(this IEnumerable<T> @enum, Action<T> mapFunction) { foreach (var item in @enum) mapFunction(item); }
当我想对一个集合中的每个元素执行相同的操作时,常常会借助于此方法实现。
直接对字符串操作,将字符串的首字母改成大写,源代码参考如下:
public static string Capitalize(this string word) { if (word.Length <= 1) return word; return word[0].ToString().ToUpper() + word.Substring(1); }
开发中经常会遇到将List<Entity>转化为DataTable,或是反之将DataTable转化为List<Entity>,stackoverflow上有很多这个需求的代码,参考下面的程序代码:
public static DataTable ToDataTable<T>(this IEnumerable<T> varlist) { DataTable dtReturn = new DataTable(); // column names PropertyInfo[] oProps = null; if (varlist == null) return dtReturn; foreach (T rec in varlist) { // Use reflection to get property names, to create table, Only first time, others will follow if (oProps == null) { oProps = ((Type) rec.GetType()).GetProperties(); foreach (PropertyInfo pi in oProps) { Type colType = pi.PropertyType; if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof (Nullable<>))) { colType = colType.GetGenericArguments()[0]; } dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); } } DataRow dr = dtReturn.NewRow(); foreach (PropertyInfo pi in oProps) { dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue (rec, null); } dtReturn.Rows.Add(dr); } return dtReturn; }
实现给数组中的每个元素赋相同的值。
public static T[] SetAllValues<T>(this T[] array, T value) { for (int i = 0; i < array.Length; i++) { array[i] = value; } return array; }
可以将一个对象序列化为Xml格式的字符串,保存对象的状态。
public static string ToXml<T>(this T o) where T : new() { string retVal; using (var ms = new MemoryStream()) { var xs = new XmlSerializer(typeof (T)); xs.Serialize(ms, o); ms.Flush(); ms.Position = 0; var sr = new StreamReader(ms); retVal = sr.ReadToEnd(); } return retVal; }
可以判断一个值是否落在区间范围值中。
public static bool Between<T>(this T me, T lower, T upper) where T : IComparable<T> { return me.CompareTo(lower) >= 0 && me.CompareTo(upper) < 0; }
类似这样的操作,下面的方法是取2个值的最大值。
public static T Max<T>(T value1, T value2) where T : IComparable { return value1.CompareTo(value2) > 0 ? value1 : value2; }
业务系统中常常会用到时间比较,如果系统是用DateTime.Now变量与DateTime.Today来作比较,前者总是大于后者的,为此需要做一个简单转化,根据需要将值转化为开始值或末值,也就是0点0分0秒,或是23时59分59秒。
public static DateTime ConverToStartDate(this DateTime dateTime) { return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0); } public static DateTime ConverToDueDate(this DateTime dateTime) { return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59); }
public static DateTime First(this DateTime current) { DateTime first = current.AddDays(1 - current.Day); return first; }
public static DateTime Last(this DateTime current) { int daysInMonth = DateTime.DaysInMonth(current.Year, current.Month); DateTime last = current.First().AddDays(daysInMonth - 1); return last; }
计算前一个数值占后一个数值的百分比,常用于统计方面。
public static decimal PercentOf(this double position, int total) { decimal result = 0; if (position > 0 && total > 0) result=(decimal)((decimal)position / (decimal)total * 100); return result; }