《CSharp In Depth》读书笔记(8)——Extension Methods

Extension methods的基本概念

作为一门完全面向对象的语言,CSharp中不可避免的要实现各种设计模式。 然而幸运的是,使用CSharp实现各种设计模式并不像在Java中那样繁琐。 因为语言本身提供了很多方便的特性帮助我们用很少量的代码实现自己的意图。 比如之前介绍过的event,和这次将要介绍的extension method。

在没有extension method的时代

我们常常会碰到这种情况,对于某些类,想要在其之上添加一些自定义的方法。 但是出于种种原因,这个已经定义好的类出于种种原因既不能被改动(比如是其他DLL中的方法), 也不允许继承(被定义为sealed)。 在这种情况下,我们只能采用其他方法。

静态方法在某种程度上可以达到我们的目的。 但是这类静态方法必须带有一个本类型的实例作为参数。 这让代码看上去总不是那么整洁,比如像这样:

public static class StringUtil
{
	public static void MyTransform(String str)
	{
		// Implement my transformation on the string
	}
}

// When using this util
StringUtil.MyTransform("Hello world");

使用extension method

Extension method解决了上述问题, 这个特性得以让新定义的方法与已经定义的类进行无缝整合。 使得我们:

// Using extension method
public static class StringUtil
{
	public static void MyTransform(this String str)
	{
		// Implement my transformation on the string
	}
}

// When using this util
new string("Hello world").MyTransform();

看上去是不是舒服了很多?

使用extension methods

LINQ

在CSharp中extension method用的最广泛的地方当属LINQ。 典型的LINQ用法如下:

var collection = Enumerable.Range(0, 10)
	.Where(x => x % 2 != 0)
	.Reverse()
	.Select(x => new { Original = x, SquareRoot = Math.Sqrt(x) } );

var collection = Enumerable.Range(-5, 11)
	.Select(x => new { Original = x, Square = x * x })
	.OrderBy(x => x.Square)
	.ThenBy(x => x.Original);

LINQ的实现大多是基于IEnumerable和IQueryable的extension method。 所以在using System.Linq;之后会发现一个实现了这些接口的类(比如Array)多出了很多新的方法。 LINQ广泛的使用extension method的做法即避免了修改原有的类与接口,又实现了对于数据集合的链式调用。 这样的结果是实现了一个可插拔的,能够大幅简化数据操作的库。 这应该是extension method应用最好的范例。

Fluent Interfaces

简单来说Fluent Interface是一种能够自我解释的代码书写方式。 而extension methods使这种方式成为了可能。 比如像下边这样写代码:

Meeting.Between("Jon")	// Returns SoloMeeting class
.And("Russell")			// Returns UntimedMeeting class
.At(8.OClock().Tomorrow());	// Returns Meeting

不过这种方法需要做的准备工作也比较多。 至于这种写法到底是不是“好”,这个见仁见智。 这里着重强调的是extension methods可以让我们在CSharp中实现这样的代码书写方式,足见其威力之强大。

关于extension methods的注意事项

正由于extension methods是威力强大的武器,所以使用这种武器的时候才应该加倍小心。 这里简单罗列一下基本的注意事项,供读者参考:

小结