【问题标题】:How to create and use a custom IFormatProvider for DateTime?如何为 DateTime 创建和使用自定义 IFormatProvider?
【发布时间】:2023-03-13 23:56:01
【问题描述】:

我试图创建一个IFormatProvider 实现来识别 DateTime 对象的自定义格式字符串。这是我的实现:

 public class MyDateFormatProvider : IFormatProvider, ICustomFormatter
 {
  public object GetFormat(Type formatType)
  {
   if (formatType == typeof(ICustomFormatter))
   {
    return this;
   }
   return null;
  }

  public string Format(string format, object arg, IFormatProvider formatProvider)
  {
   if(arg == null) throw new ArgumentNullException("arg");
   if (arg.GetType() != typeof(DateTime)) return arg.ToString();
   DateTime date = (DateTime)arg;
   switch(format)
   {
    case "mycustomformat":
     switch(CultureInfo.CurrentCulture.Name)
     {
      case "en-GB":
       return date.ToString("ddd dd MMM");
      default:
       return date.ToString("ddd MMM dd");
     }
    default:
     throw new FormatException();
   }
  } 

我期待能够像这样在DateTime.ToString(string format, IFormatProvider provider) 方法中使用它,但是:

DateTime d = new DateTime(2000, 1, 2);
string s = d.ToString("mycustomformat", new MyDateFormatProvider());

在该示例中,在美国文化中运行,结果为 "00cu0Ao00or0aA",显然是因为正在解释标准的 DateTime 格式字符串。

但是,当我以下列方式使用同一个类时:

DateTime d = new DateTime(2000, 1, 2);
string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d);

我得到了我的期望,即"Sun Jan 02"

我不明白不同的结果。谁能解释一下?

谢谢!

【问题讨论】:

    标签: c# iformatprovider


    【解决方案1】:

    简短的解释是,虽然

    DateTime.ToString(string format, IFormatProvider provider)
    

    允许您传递任何实现IFormatProvider 作为其参数之一,它实际上只支持在其代码中实现IFormatProvider 的两种可能类型:

    DateTimeFormatInfoCultureInfo

    如果您的参数无法转换为(使用as)作为其中一个或那些,则该方法将默认为CurrentCulture

    String.Format 不受此限制。

    【讨论】:

      【解决方案2】:

      使用 Reflector 检查DateTime.ToString 方法表明DateTime 结构使用DateTimeFormatInfo.GetInstance 方法来获取要用于格式化的提供程序。 DateTimeFormatInfo.GetInstance 从传入的提供程序请求DateTimeFormatInfo 类型的格式化程序,从不请求ICustomFormmater,因此如果没有找到提供程序,它只返回DateTimeFormatInfoCultureInfo 的实例。似乎DateTime.ToString 方法不像StringBuilder.Format 方法那样尊重ICustomFormatter 接口,正如您的String.Format 示例所示。

      我同意DateTime.ToString 方法应该支持ICustomFormatter 接口,但目前似乎不支持。这在 .NET 4.0 中可能已经或将要发生变化。

      【讨论】:

      • 感谢您的详细回复。我在想我误解了接口和预期的实现,所以很高兴知道这是古怪的 DateTime 实现:-)
      【解决方案3】:

      使用扩展方法:)

      public static class FormatProviderExtension
          {
              public static string FormatIt(string format, object arg, IFormatProvider formatProvider)
              {
                  if (arg == null) throw new ArgumentNullException("arg");
                  if (arg.GetType() != typeof(DateTime)) return arg.ToString();
                  DateTime date = (DateTime)arg;
                  switch (format)
                  {
                      case "mycustomformat":
                          switch (CultureInfo.CurrentCulture.Name)
                          {
                              case "en-GB":
                                  return date.ToString("ddd dd MMM");
                              default:
                                  return date.ToString("ddd MMM dd");
                          }
                      default:
                          throw new FormatException();
                  }
              }
      
              public static string ToString(this DateTime d, IFormatProvider formatProvider, string format)
              {
                  return FormatIt(format, d, formatProvider);
              }
          }
      

      【讨论】:

      • 是的,看起来扩展方法是我唯一的选择。感谢您的回复!
      猜你喜欢
      • 2015-11-26
      • 2019-01-02
      • 2011-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-08
      相关资源
      最近更新 更多