如何告诉类型格式化输出的格式

分析问题

  IFormatProvider的设计思想是站在类型使用者的角度来提供格式化的方法,这和前文中介绍的IFormattable接口站在类型设计者的角度不同。IFormatProvider只包含了一个方法:object GetFormat(Type formatType)。该方法根据对象的类型给出了一个格式化器,IFormatProvider试图告诉类型用该格式化器去做格式化输出。当然最终的选择权仍然在类型设计者手中,现在在分析一下之前的代码,IFormattable.ToString方法的一开始就对IFormatProvider参数进行判断,当其不为null时,就完全采用使用者提供的格式化方法,这么做是一种信任类型用户的方式,当然,类型的设计者也可以完全不理会IFormatProvider提供的格式化器,这样做确保了类型的安全,但是却提供了非常不友好的接口。

  IFormatProvider的GetFormat方法返回一个object类型的格式化器,在通常情况下,一个实现了ICustomFormatter接口的类型对象会被返回,但这一点是无法保证的,以下代码展示了一个常用的实现IFormatProvider的方法,它在之前代码的基础上,提供了IFormatProvider的实现。

using System;

namespace Test
{
    class UseIFormatProvider:IFormattable
    {
        public DateTime _time;

        public UseIFormatProvider(DateTime time)
        {
            _time = time;
        }
        //重写ToString方法
        public override string ToString()
        {
            return "Object.ToString()";
        }



        public string ToString(string format, IFormatProvider formatProvider)
        {
            //这里判断使用者是否提供了格式化器
            if (formatProvider!=null)
            {
                ICustomFormatter fmt = formatProvider.GetFormat(this.GetType()) as ICustomFormatter;
                if (fmt!=null)
                {
                    return fmt.Format(format, this, formatProvider);
                }
            }
            //这里实现格式化输出
            switch (format)
            {
                case "ld":
                    return _time.ToLongDateString();
                case "lt":
                    return _time.ToLongTimeString();
                case "lsd":
                    return _time.ToShortDateString();
                case "st":
                    return _time.ToShortTimeString();
                case "G":
                case "":
                case null:
                default:
                    return _time.ToString();
            }
        }

        static void Main()
        {
            UseIFormatProvider use = new UseIFormatProvider(DateTime.Now);
            IFormatProvider provider = new MyProvider();
            Console.WriteLine(use);//调用的是IFormattable.ToString()方法
            //使用这提供格式化方法,格式化字符串不再起作用
            Console.WriteLine(use.ToString("lt", provider));
            Console.WriteLine(use.ToString("st", provider));

            Console.Read();
        }
    }

    class MyProvider : ICustomFormatter, IFormatProvider
    {
        //实现了ICustomFormatter的Format方法
        //实际的格式化工作在这里完成
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            UseIFormatProvider obj = arg as UseIFormatProvider;
            if (obj==null)
            {
                return arg.ToString();
            }
            return obj._time.ToString("yyyy-MM-dd hh:mm:ss");
        }

        //本类型可以实现对UseIFormatProvider类型的格式化
        public object GetFormat(Type formatType)
        {
            if (formatType==typeof(UseIFormatProvider))
            {
                return this;
            }
            else
            {
                return null;
            }
        }
    }

}

  如以上代码所示,MyProvider的GetFormat方法返回了一个实现了ICustomFormat接口的类型对象,这在以上代码中就是MyProvider的对象本身,并且在Format方法中实现了具体的格式化方法。

  在通常情况下,由类型使用者来实现格式化并不容易,因为他不能随心所欲地访问类型的内部成员。而类型的设计者实现格式化输出时,又势必很难覆盖所有类型使用这的需求,这就需要两者进行有效的协调。就如以上代码所展示的那样,类型设计者实现了一部分常用的格式化需求,并且允许使用者提供他们自己的格式化方法。

答案

  IFormatProvider让类型的使用者有机会提供格式化的方法。GetFormat方法返回一个格式化器,在通常情况下,该格式化器的类型是一个实现了ICustomFormatter的类型对象。IFormatProvider接口和IFormattable接口一起可以实现灵活强大的格式化输出。

 

posted on 2014-08-19 16:54  wangjinpeng_study  阅读(152)  评论(0编辑  收藏  举报

导航