建议101:使用扩展要领,向现有类型“添加”要领
考虑如何让一个sealed类型具备新的行为。以往我们会创建一个包装器类,然后为其添加要领,而这看上去一点儿也不优雅。我们也许会考虑改削设计,直接改削sealed类型,然后为其颁布一个新的版本,,但这依赖于你拥有全部的源码。更多的时候,我们会采纳针对第三方公司供给的API进行编程的方法。对付我们来说,FCL是一组第三方公司(微软)供给给我们的最好的API。
包装类的编码形式如下:
class Program
{
static void Main(string[] args)
{
Student student = new Student();
Console.WriteLine(StudentConverter.GetSexString(student));
}
}
public static class StudentConverter
{
public static string GetSexString(Student student)
{
return student.GetSex() == true ? "男" : "女";
}
}
public class Student
{
public bool GetSex()
{
return false;
}
}
可以看到,Student类型只供给了一个GetSex要领,它返回了一个bool值的功效。我们需要的是要将一个bool值转换为一个字符串,StudentConverter就是为了满足需求而创建的一个包装器类。挪用者的代码看起来就应该是这样的:
Console.WriteLine(StudentConverter.GetSexString(student));
但是我们知道,可以有更优美的形式让挪用者像挪用Student类型的实例要领一样来挪用GetSexString了。这种更好的方法就是扩展要领:
class Program { static void Main(string[] args) { Student student = new Student(); Console.WriteLine(student.GetSexString()); } } public static class StudentExtension { public static string GetSexString(this Student student) { return student.GetSex() == true ? "男D" : "女?"; } }
扩展要领除了让挪用着可以像挪用类型自身的要领一样去挪用扩展要领外,它还有一些其他的主要长处:
可以扩展密封类型;
可以扩展第三方措施集中的类型;
扩展要领可以制止不须要的深度担任体系。
扩展要领还有一些必需遵循的要求:
扩展要领必需在静态类中,而且该类不能是一个嵌套类;
扩展要领必需是静态的;
扩展要领的第一个参数必需是要扩展的类型,而且必需加上this关键字;
不撑持扩展属性、事件。
值得注意的一点是,扩展要领还能够扩展接口。这让接口看上去也是可以扩展的。扩展要领的这个特性被广泛应用于供给LINQ盘问成果的Enumerable类和Queryable类中。以Enumerable为例,针对IEnumerable<T>接口供给了非常丰富的一种要领,如Select:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) { //具体代码省略 }
它相当于让担任自IEnumerable<T>接口的任何子类都拥有了Select要领,而这些Select要领在用者看来,就仿佛是IEnumerable<T>接口所声明的一样。