1.1.1 摘要
相信大家对ToString()方法再熟悉不过了,由于该方法是.NET程序中最常用的方法之一,我们除了可以直接调用ToString()方法之外,.NET中的某些方法也隐式调用ToString()方法(WPF,Windows Form和Silverlight等)。
1.1.2 正文
首先让我们了解一下ToString()的由来,它是由Object类提供一个虚的方法,ToString()方法返回一个字符串显示调用该方法对象的类型,Object类中实现如下。
现在我们知道Object类提供的是一个虚的ToString()方法,表明.NET也提供我们重写ToString()方法,接来下让我们定义一个Customer类,然后再使用Console.WriteLine()方法隐式调用Customer类的ToString()方法输出,注意我们现在还没有重写ToString方法,所以我们调用的是Object类的ToString()方法。
图1输出类型字符串
重新ToString()方法
通过上图我们可以很明确的说明了在没有重新ToString()方法时,我们调用的是父类Object的ToString()方法。不但它的输出不怎么make sence,而且它并没有输出我们需要的值,那么接下来让我们重写ToString()方法。
上面我们重写了ToString()方法返回Name,Revenuehe和Tel属性,接着我们使用WriteLine()方法隐式调用ToString()方法(.NET提供显式和隐式调用ToString()的方法,如:Console.WriteLine、String.Format和.NET控件等)。
虽然简单的ToString()方法很多时候已经可以满足我们的需求,但有时候我们还需要功能更强的方法来格式化输出字符串。(如:电话号码,日期和邮编等格式)
要实现上述格式,我们可以通过实现IFormattable 接口来解决这个问题。 IFormattable 接口包含了一个重载的ToString()方法,它允许我们为类型指定某种格式信息。当我们需要为类型创建不同形式的字符串输出时,实现这个接口就显得很有用了。
-
实现IFormattable接口
现在我们修改一下我们的Customer类,让它实现IFormattable接口,然后重写ToString()方法,实现如下:
图2 IFormattable的实现
使我们设计符合OCP
现在我们的Customer类实现了IFormattable接口,然后重写了ToString()方法,接着提供三种格式化类型输出,OK现在我们的输出字符串有更好的自定义格式了,但用户需求的格式是在不断的变化,我们无法估计和预知用户需求的输出格式,难道每当遇到不符合用户要求的格式我们都要在switch中添加吗?我们的确可以这样做,这种做法看上去是直截了当,但这不符合设计模式的OCP原则。幸运的是.NET提供了符合OCP原则的实现方法,通过实现IFormattable接口使得实现该接口的类对StringFomat()修改关闭,当实现ICustomFormatter接口的类对StringFomat()扩展开放。
“Software entities (classes, modules, functions, etc.) should be open for extension,
but closed for modification [Martin, p.99]”
现在我们添加自定义类CustomFormatProvider,通过它可以扩展Customer的输出字符串的格式类型,而且避免了对Customer类的修改遵守了OCP,然后再实现接口IFormatProvider和ICustomFormatter,在Format()方法中实现字符串输出格式。
图4自定义字符串格式
图5自定义格式实现框架
上面的GetFormat()方法创建一个实现ICustomFormatter接口的对象,而且通过重写Format()方法来自定义输出字符串格式,通过传递不同format参数以便指定不同格式选项。
1.1.3 总结
不管一个类是否实现了IFormattable接口,我们都可以为其创建 IFormatProvider 和 ICustomFormatter 的实现类。因此即使一个类的原来没有提供合理的ToString()行为,我们仍然可以为其提供格式化支持。当然,作为一个类的外部访问者,我们只能通过访问其中的公有属性和数据成员来构造字符串。虽然编写格式提供者类(分别实现IFormatProvider 和 ICustomFormatter)需要很多工作,且其目的仅仅是为了得到一个字符串。但是,一旦使用了这种方式来实现我们自己定义的字符串输出,它们将在.NET 框架的各个地方得到支持。
现在,再让我们回到类这一角色上来。重写 Object.ToString()是为类提供字符串表示的最简单方式。每当我们创建一个类型时,都要提供该方法。它应该是我们的类型最明显、最常用的一种表示。而且只有在一些比较少的情况下,当我们期望为类型提供更复杂的输出格式时,才应该实现IFormattable 接口。它为“类型的用户定制类型的字符 串输出”提供了一种标准的方式。如果我们没有做这些工作,用户就要自己来实现自定义格式化器。那样的做法需要更多的代码,因为用户处于类外,无法访问对象 的内部状态。