Effective C# Item5:总是提供ToString()方法

    C#中,System.Object默认提供了ToString()方法, 它会返回当前对象的完整类型名称,即命名空间 + "." + 类名,这种信息,对于类的使用者或者终端用户来说,可读性都很低,因此,建议在新建一个类时,重写ToString()方法。

    如果不重写ToString()方法,那么为了向用户显示一些有意义的信息,就需要在每个调用这个类的地方,编写相同的代码,这样会造成很大的代码冗余,为了消灭这种情况,我们还是在新建类时,就完成这个工作吧。

    关于如何重写ToString()方法, 有以下两种方式。

    第一种方式比较简单,只是单纯的重写Object类的ToString()方法,这种方法返回的信息比较简单,调用方可选择的余地比较小;第二种方式比较复杂,我们可以让类实现IFormatter接口,这个接口提供了一个ToString方法。

    接下来,我们分别以示例来说明上述两种方法。

    首先是不重写ToString()方法的类,表明一个员工的基本信息。

代码
1 public class BaseEmployee
2 {
3 private string m_strName;
4
5 public string Name
6 {
7 get { return m_strName; }
8 set { m_strName = value; }
9 }
10 private string m_strSex;
11
12 public string Sex
13 {
14 get { return m_strSex; }
15 set { m_strSex = value; }
16 }
17 private string m_strAddress;
18
19 public string Address
20 {
21 get { return m_strAddress; }
22 set { m_strAddress = value; }
23 }
24 }

    然后,我们来看针对上述第一种方式,如何实现。

1 public class SimpleEmployee : BaseEmployee
2 {
3 public override string ToString()
4 {
5 return base.Name;
6 }
7 }

    上述代码实现了第一种方式,它重写了ToString()方法,向调用方返回当前对象的Name属性的值。

    再来看以下的代码如何实现第二种方式。

代码
1 public class ComplexEmployee : BaseEmployee, IFormattable
2
3 {
4 public string ToString(string format, IFormatProvider formatProvider)
5 {
6 //throw new NotImplementedException();
7   if (formatProvider != null)
8 {
9 ICustomFormatter fmt = formatProvider.GetFormat(this.GetType()) as ICustomFormatter;
10 if (fmt != null)
11 {
12 return fmt.Format(format, this, formatProvider);
13 }
14 }
15
16 switch (format)
17 {
18 case "n":
19 return base.Name;
20 case "s":
21 return base.Sex;
22 case "a":
23 return base.Address;
24 case "ns":
25 return string.Format("{0,20}, {1,15}", base.Name, base.Sex);
26 case "na":
27 return string.Format("{0,15}, {1,15}", base.Name, base.Address);
28 case "G":
29 default:
30 return base.Name;
31 }
32 }
33
34 public override string ToString()
35 {
36 return "Just For Test";
37 }
38 }

    上述代码中,我们实现了IFormatter接口,其中包含了ToString()方法,并且我们还重写了Object的ToString()方法。

    接下来是针对上述两种方式的测试代码,如下。

代码
/// <summary>
/// test ToString() method
/// </summary>
private static void TestToString()
{
BaseEmployee employee
= new BaseEmployee();
employee.Name
= "Wing";
employee.Sex
= "M";
employee.Address
= "BeiJing China";
Console.WriteLine(employee);

SimpleEmployee simpleE
= new SimpleEmployee();
simpleE.Name
= "XXX";
simpleE.Sex
= "NA";
simpleE.Address
= "Vernus";
Console.WriteLine(simpleE);

ComplexEmployee complexE
= new ComplexEmployee();
complexE.Name
= "YYY";
complexE.Sex
= "F";
complexE.Address
= "Moon";
Console.WriteLine(complexE);
Console.WriteLine(complexE.ToString());
Console.WriteLine(complexE.ToString(
"na", null));
}
}

    上述代码的运行结果如下。

    我们在测试代码中,有以下两行代码,执行效果非常有趣。

Console.WriteLine(complexE);

Console.WriteLine(complexE.ToString());

    在类实现了IFormatter接口的情况下,上述第一行代码会执行IFormatter接口中的ToString方法,而第二行代码会执行我们重写过的Object类的ToString()方法。

    我们在实现IFormatter接口的ToString()方法中,有以下语句。

代码
1 if (formatProvider != null)
2 {
3 ICustomFormatter fmt = formatProvider.GetFormat(this.GetType()) as ICustomFormatter;
4 if (fmt != null)
5 {
6 return fmt.Format(format, this, formatProvider);
7 }
8 }

    这表明我们可以根据业务的需要,自己定制Formatter,例如,我们可以编写如下代码。

代码
1 internal class EmployeeFormatProvider : IFormatProvider
2 {
3
4 #region IFormatProvider Members
5
6 public object GetFormat(Type formatType)
7 {
8 if (formatType == typeof(ICustomFormatter))
9 {
10 return new EmployeeFormatter();
11 }
12 return null;
13 }
14
15 #endregion
16
17 private class EmployeeFormatter : ICustomFormatter
18 {
19 public string Format(string format, object arg, IFormatProvider formatProvider)
20 {
21 ComplexEmployee c = arg as ComplexEmployee;
22 if (c == null)
23 {
24 return arg.ToString();
25 }
26
27 return string.Format("{0,50}, {1,5}, {1,20}", c.Name, c.Sex, c.Address);
28 }
29 }
30 }

    在我们自定义好Formatter后,不能再直接以ToString()的方式使用,而是要以String.Format()的方式使用,例如:

Console.WriteLine(string.Format(new EmployeeFormatProvider(), string.Empty, complexE));

    我感觉实际应用中,能够使用到自定义Formatter的地方,应该非常小,因此,主要关注上面第一种和第二种方式就可以解决日常工作中的大部分问题。

原文地址:https://www.cnblogs.com/wing011203/p/1639264.html