如何为DateTime创建和使用自定义IFormatProvider?
我试图创建一个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"
我不明白不同的结果。 有人能解释一下吗
谢谢!
使用Reflector检查DateTime.ToString
方法显示DateTime
结构使用DateTimeFormatInfo.GetInstance
方法来获取要用于格式化的提供程序。 DateTimeFormatInfo
从传入的提供程序请求类型为DateTimeFormatInfo
的格式化程序,从不为ICustomFormmater
,因此如果找不到提供程序,它只返回DateTimeFormatInfo
或CultureInfo
的实例。 看起来DateTime.ToString
方法不像StringBuilder.Format
方法那样遵守ICustomFormatter
接口,正如您的String.Format
示例所示。
我同意DateTime.ToString
方法应该支持ICustomFormatter
接口,但它目前似乎不是。 这可能已经改变或将在.NET 4.0中发生变化。
简短的解释是,虽然
DateTime.ToString(string format, IFormatProvider provider)
允许您将实现IFormatProvider
任何内容作为其中一个参数传递,它实际上只支持在其代码中实现IFormatProvider
2种可能类型:
DateTimeFormatInfo
或CultureInfo
如果您的参数不能(或使用as
)作为其中任何一个或那些参数,则该方法将默认为CurrentCulture
。
String.Format
不受此类限制的限制。
使用扩展方法:)
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); } }