一 发现问题
扩展方法的思考来源于这样的一次经历:在项目中开发程序时,经常这样使用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或第三方控件中的某些类),提供了功能扩展的可能。