C#有关IFormatProvider的实践

701 阅读4分钟

对于C#中的IFormatProvider的理解一直是模棱两可的,有时候感觉理解了,有时候又没有理解,昨天索性好好去理解一下。找了一些资料,然后整理了这篇笔记。

官方定义

提供一种机制,用于检索对象以控制格式化。

public interface IFormatProvider

注解

该 IFormatProvider 接口提供一个对象,该对象提供格式设置和分析操作的格式信息。 格式设置操作将类型的值转换为该值的字符串表示形式。 典型的格式设置方法是 ToString 类型的方法,以及 Format。 分析操作将值的字符串表示形式转换为具有该值的类型。 典型的分析方法是 Parse 和 TryParse

接口IFormatProvider由单个方法组成。 IFormatProvider.GetFormat GetFormat 是回调方法:分析或格式化方法调用它并传递一个 Type 对象,该对象表示格式设置或分析方法期望的对象类型将提供格式设置信息。 该方法 GetFormat 负责返回该类型的对象。

IFormatProvider 实现通常通过格式化和分析方法隐式使用。 例如,该方法 DateTime.ToString(String) 隐式使用 IFormatProvider 表示系统当前区域性的实现。 IFormatProvider 还可以通过具有类型 IFormatProvider参数的方法(如 Int32.Parse(String, IFormatProvider) 和 String.Format(IFormatProvider, String, Object[]))显式指定实现。

.NET Framework还支持自定义格式设置。 这通常涉及创建实现这两种格式 IFormatProvider 和 ICustomFormatter格式设置类。 然后,此类的实例作为参数传递给执行自定义格式设置操作的方法

实例

一 自定义格式

  public class AcctNumberFormat : IFormatProvider, ICustomFormatter
    {
        private const int ACCT_LENGTH = 12;

        //public string Format(string format, object arg, IFormatProvider formatProvider)
        //{
        //    throw new NotImplementedException();
        //}

        //public object GetFormat(Type formatType)
        //{
        //    throw new NotImplementedException();
        //}

        // 就是先调用IFormatProvider,然后再调用 ICustomFormatter 。
     public object GetFormat(Type formatType) 

     {

         if (formatType == typeof(ICustomFormatter))

             return this;//this 就是 AcctNumberFormat

            else

             return null;

     }

     public string Format(string fmt, object arg, IFormatProvider formatProvider) //这个是实现ICustomFormatter中的方法
        {
         // Convert argument to a string
         string result = arg.ToString();

         // If account number is less than 12 characters, pad with leading zeroes

         if (result.Length < ACCT_LENGTH)

             result = result.PadLeft(ACCT_LENGTH, '0');//少于12个字符就用0填充

         // If account number is more than 12 characters, truncate to 12 characters

         if (result.Length > ACCT_LENGTH)

             result = result.Substring(0, ACCT_LENGTH);//大于12个字符,就截取12个

         // Add hyphens for formatting code "H"

         if (!String.IsNullOrEmpty(fmt) && fmt.ToUpper() == "H")//如果设置的格式等于H 就按照下面的格式显示数据
             return result.Substring(0, 5) + "-" + result.Substring(5, 3) + "-" + result.Substring(8);
         // Return string representation of argument for any other formatting code
         else
             return result;

     }
    }

二 测试代码

          long acctNumber;

            PersonTest p1 = new PersonTest { FirstName = "XY", LastName = "CN" };
            PersonFormatter pf = new PersonFormatter();
            string s1 = p1.ToString("CN", pf); //这个很好理解
            Console.WriteLine(s1);
            string s2 = p1.ToString("EN", pf);
            Console.WriteLine(s2);

      acctNumber = 104254567890;

            // 表示参数 acctNumber必须以{0:H}格式展示,并且按照区域性特定的格式设置信息。所以可以把把参数和格式传入到 AcctNumberFormat里面去。
            Console.WriteLine(String.Format(new AcctNumberFormat(), "{0:H}", acctNumber));//这是规定,所以里面的逻辑原理不要去探讨了。  链接:https://learn.microsoft.com/zh-cn/dotnet/api/system.string.format?view=net-7.0

            Console.WriteLine(String.Format(new AcctNumberFormat(), "{0}", acctNumber));

            acctNumber = 14567890;

            Console.WriteLine(String.Format(new AcctNumberFormat(), "{0:H}", acctNumber));

            Console.WriteLine(String.Format(new AcctNumberFormat(), "{0}", acctNumber));

            acctNumber = 18779887654111;

            Console.WriteLine(String.Format(new AcctNumberFormat(), "{0:H}", acctNumber));

            Console.WriteLine(String.Format(new AcctNumberFormat(), "{0}", acctNumber));

三运行结果

image.png

有关这个String.Format(new AcctNumberFormat(), "{0}", acctNumber) 的理解。

image.png

这个表格说明了很清楚就是规定,所以不需要探讨里面具体实现了。

Format(IFormatProvider, String, Object, Object, Object)将字符串中的格式项替换为三个指定对象的字符串表示形式。 参数提供区域性特定的格式设置信息。
Format(String, Object, Object, Object)将字符串中的格式项替换为三个指定对象的字符串表示形式。
Format(IFormatProvider, String, Object, Object)将字符串中的格式项替换为两个指定对象的字符串表示形式。 参数提供区域性特定的格式设置信息。
Format(String, Object, Object)将字符串中的格式项替换为两个指定对象的字符串表示形式。
Format(IFormatProvider, String, Object)将指定字符串中的一个或多个格式项替换为对应对象的字符串表示形式。 参数提供区域性特定的格式设置信息。
Format(IFormatProvider, String, Object[])将字符串中的格式项替换为指定数组中相应对象的字符串表示形式。 参数提供区域性特定的格式设置信息。
Format(String, Object[])将指定字符串中的格式项替换为指定数组中相应对象的字符串表示形式。
Format(String, Object)将字符串中的一个或多个格式项替换为指定对象的字符串表示形式。

延伸学习:String.Format 方法 (System) | Microsoft Learn 原文:www.cnblogs.com/bear831204/…

四 帮助理解学习

 //https://www.cnblogs.com/cncc/p/8078599.html
    public class PersonTest : IFormattable
    {
        public string FirstName { set; get; }
        public string LastName { set; get; }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            ICustomFormatter customFormatter = formatProvider as ICustomFormatter; //formatProvider 就是 PersonFormatter 用接口 ICustomFormatter 接受 PersonFormatter,然后调用方法
            if (customFormatter == null) return this.ToString();
            return customFormatter.Format(format, this, null);// this 是 PersonTest
        }
    }

    public class PersonFormatter : IFormatProvider, ICustomFormatter
    {
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            PersonTest person = arg as PersonTest;
            switch (format)
            {
                case "CH": return $"{person.LastName} {person.FirstName}";
                case "EN": return $"{person.FirstName} {person.LastName}";
                default: return $"{person.LastName} {person.FirstName}";
            }
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter)) return this;
            return null;
        }

原文:www.cnblogs.com/cncc/p/8078…