一 发现问题
扩展方法的思考来源于这样的一次经历:在项目中开发程序时,经常这样使用List<T>和Dictionary<K,V>。
<span style="white-space:pre"> </span> List<string> listTest = new List<string>(); listTest.ForEach(item => { //方法体略 }); Dictionary<string, string> dicTest = new Dictionary<string, string>(); dicTest.ForEach(item => { //方法体略 });
二 提出问题
使用的时候也从来没想过,为什么可以这么用,底层是怎么实现的,直到……..
有那么一次,我自己写了个小项目,没有使用平台的类库,突然发现List<T>还可以这么使用,但是Dictionary<K,V>却不可以使用这个方法了,这是怎么回事呢?虽然直接使用迭代器完全可是实现相同的功能,但是本着不讲究是发现问题的源动力,我还是(ˇ?ˇ)
想~一探究竟。
首先F12查看List<T>的底层,发现是这么实现的:
public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable { <span style="white-space:pre"> </span>public void ForEach(Action<T> action) { if (action == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } int num = this._version; for (int i = 0; i < this._size; i++) { if ((num != this._version) && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) { break; } action(this._items[i]); } if ((num != this._version) && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); } } }
三 分析问题
在泛型集合类中,直接写了这个方法的实现,所以可以由对象直接调用这个方法。而Dictionart<K,V>是怎么实现的呢?
<span style="white-space:pre"> </span>public static class IEnumerableExtension { <span style="white-space:pre"> </span> public static void ForEach<T>(this IEnumerable<T> data, Action<T> action) { if (data != null && action != null) { foreach (T item in data) { action(item); } } } }
这个方法及实现并不是直接写到了字典类或者父类中,原来这是一个扩展类。那么扩展类究竟是怎么回事呢?我们平时会用到吗?应该如何使用呢?
四 理论支持
CSDN官方解释:扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其它方式修改原始类型。
这里的添加带有双引号,原文已经说了,它并不是真正的给类型添加方法,而只是在程序中对它进行了扩展,所以并不需要重新编译和发布底层类库。
好了,理论支持有了,来个实践,选用网上已经实现的例子:string类型有个IsNullOrEmpty方法判断字符串是否为null或为空,比如:
<span style="white-space:pre"> </span> string strTest = string.Empty; bool resultIsNullOrEmpty = strTest.IsNullOrEmpty();
现在,我们还需要进一步判断,赋值内容字符串是否为空字符串。代码如下:
public static class ExtentdHelper { public static bool strIsNullOrWhiteSpace(this string str) { bool strIsNullOrWhiteSpace = false; if (string.IsNullOrEmpty(str) || str.Length == 0) { strIsNullOrWhiteSpace = true; } return strIsNullOrWhiteSpace; } } <span style="white-space:pre"> </span>static void Main(string[] args) { string strTest = ""; Console.WriteLine(strTest.IsNullOrWhiteSpace()); Console.ReadKey(); }
效果图:
扩展方法的约束:
1
扩展方法必须是静态方法,类必须是静态类,但它是通过实例调用的。
2
第一个参数必须有this关键字,用于确定扩展方法的目的类型。
3可以使用扩展类或接口,但是不能重写扩展方法。
五 解决问题
好了,理论支持有了,我们回头看文章开头小编提出的问题,如何给Dictionary<K,V>编写这个扩展方法呢?
public static class ExtentdHelper { <span style="white-space:pre"> </span>public static void ForEach<T>(this IEnumerable<T> data ,Action<T> action) { if (data != null && action != null) { foreach (T item in data) { action(item); } } } }
调用这个扩展方法:
<span style="white-space:pre"> </span>static void Main(string[] args) { Dictionary<string, string> dicTest = new Dictionary<string, string>(); dicTest.Add("1","a"); dicTest.Add("2","b"); dicTest.Add("3","c"); dicTest.ForEach(item => { Console.WriteLine("key: " + item.Key + " value: " + item.Value); }); Console.ReadKey(); }
效果图:
六 总结:
扩展方法好处:
1
减少程序中臃肿的代码,使代码更加简洁,更具阅读性。
2
可以在不继承和重写的情况下扩展类型的功能,使程序结构更加灵活。
3
为一些不能不能被继承或修改的类或接口(比如string或第三方控件中的某些类),提供了功能扩展的可能。
版权声明:本文为博主原创文章,未经博主允许不得转载。