彻底学通string.Format以及IFormattable,IFormatProvider,ICustomFormatter(2)

 3.ToString带有自定义格式化参数的理解

  上面讲到的ToString都是不带格式化参数的,像  {1:yyyy-MM-dd} 这样的情况是没法处理的,也许有人会说像 DateTime.Now.ToString("yyyy-MM-dd") 这样的情况自己去重载一个ToString方法就可以了,果真如此吗? 下面就测试一下:

public   class  PersonWithToString
    {
        
public   string  Name {  get set ; }

        
public   override   string  ToString()
        {
            
return  Name;
        }

        
public   string  ToString( string  format)
        {
            
switch  (format)
            {
                
case   " UPP " :
                    
return  Name.ToUpper();
                
case   " LOW " :
                    
return  Name.ToLower();
                
default :
                    
return  Name;
            }
        }
    }
var msg9  =   string .Format( " Hello Cnblogs, I am {0},Today is {1:yyyy-MM-dd} {2}. " ,
                                  
new  PersonWithToString() { Name  =   " Zhezhe "  }.ToString( " UPP " ), DateTime.Now, DateTime.Now.DayOfWeek);
            Console.WriteLine(msg9);

  msg9的实际输出为 Hello Cnblogs, I am ZHEZHE,Today is 2010-07-30 Friday.  这个正是我们需要的,当然,这个肯定是对的,要不然就是.net的bug了。

  接下来再看看下面的:

var msg8  =   string .Format( " Hello Cnblogs, I am {0:UPP},Today is {1:yyyy-MM-dd} {2}. " ,
                                  
new  PersonWithToString() { Name  =   " Zhezhe "  }, DateTime.Now, DateTime.Now.DayOfWeek);

  实际输出是: Hello Cnblogs, I am Zhezhe,Today is 2010-07-30 Friday.  并不是我们所期望的。实际上上面的代码是调用了PersonWithToString类的不带参数的ToString()方法。言外之意就是  {0:UPP}这样的格式实际上内部处理的是和  {0}一样的效果了。在1中提到了分解的原理用了类似两个字,实际情况并不是这么简单。

  {0:UPP} 真正调用的方法签名是    string ToString(string format,IFormatProvider formatProvider)

  而且也不是直接调用该对象的此方法。而是通过 IFormattable 接口实现的方法。

  现在定义实现了该接口的 Person2类。  

  
  
public class Person2 : IFormattable
{
public string Name { get ; set ; }

public override string ToString()
{
return Name;
}

#region IFormattable Members

public string ToString( string format, IFormatProvider formatProvider)
{
if ( string .IsNullOrEmpty(format))
return ToString();

switch (format)
{
case " UPP " :
return Name.ToUpper();
case " LOW " :
return Name.ToLower();
default :
return Name;
}
}

#endregion
}

    运行一下代码得到预期的结果:

   // 使用实现了IFormattable接口的Person2对象
var msg10  =   string .Format( " Hello Cnblogs, I am {0:UPP},Today is {1:yyyy-MM-dd} {2}. " ,
new  Person2() { Name  =   " ZhezheToUpper "  }, DateTime.Now, DateTime.Now.DayOfWeek);
Console.WriteLine(msg10);

   ZhezheToUpper已经输出成全部大写形式了。

  既然{0:UPP}会调用接口定义的ToString方法,那么{0}呢? 如果该类没有实现IFormattable接口,上面已经说了,会调用重载的或者是基类的ToString()方法。但是如果该类已经实现了IFormattable接口,那么{0}也不会去调用重载的或者是基类的ToString()方法了,它始终是去调用 接口定义的 ToString方法。下面具体印证一下:

  
  
public class Person3 : IFormattable
{
public string Name { get ; set ; }

public override string ToString()
{
return Name;
}

#region IFormattable Members

public string ToString( string format, IFormatProvider formatProvider)
{
if ( string .IsNullOrEmpty(format))
return Name + " IFormattable Method " ;

switch (format)
{
case " UPP " :
return Name.ToUpper();
case " LOW " :
return Name.ToLower();
default :
return Name + " IFormattable Method " ;
}
}

#endregion
}

  运行下面的测试代码:

var msg11  =   string .Format( " Hello Cnblogs, I am {0},Today is {1:yyyy-MM-dd} {2}. " ,
                                  
new  Person3() { Name  =   " ZhezheToUpper "  }, DateTime.Now, DateTime.Now.DayOfWeek);
            Console.WriteLine(msg11); 

  输出为: Hello Cnblogs, I am ZhezheToUpper IFormattable Method,Today is 2010-07-30 Friday。

  证明了确实是调用了接口定义的方法,而不是重载的ToString方法,否则是输出ZhezheToUpper

  再来看一下Person2中实现的ToString方法:

   if (string.IsNullOrEmpty(format))
          return ToString();
  如果是刚才的{0}不带格式化参数的调用,则format参数传过来的是null值,这里需要自己判断,如果是null值,一般情况下是手工去调用重载的ToString()方法。
  所以Person2的做法是好的,而Person3中的做法是不好的,Person3只是为了测试分辨出调用的是哪个方法才这么设计的。

  总结:一.对于实现IFormattable 接口时,如果format参数为null(即不带格式化参数的情况,如{0})则应该调用重载的 ToString()方法,而不应该自己去另外写代码。

       二.如果找不到相应的格式化参数,例如{0:AAA},在Person2的switch中并无匹配的AAA,这种情况一般也应该去调用重载的 ToString()方法。

  否则就会出: 

  // 以下两个输出结果不一样,是不合理的
var msg12  =   string .Format( " Hello Cnblogs, I am {0},Today is {1:yyyy-MM-dd} {2}. " , new  Person3() { Name  =   " ZhezheToUpper "  }, DateTime.Now, DateTime.Now.DayOfWeek);
Console.WriteLine(msg12);

var msg13 
=   string .Format( " Hello Cnblogs, I am {0},Today is {1:yyyy-MM-dd} {2}. " , new  Person3() { Name  =   " ZhezheToUpper "  }.ToString(), DateTime.Now, DateTime.Now.DayOfWeek);
Console.WriteLine(msg13);

  不同的结果的情况,上面的输出结果不同:

  这是不好的设计。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值