This post provides an internal overview of IFormatProvider & ICustomFormatter interfaces, and they way they are handled by .NET.
IFormatProvider is a .NET Framework Interface that should be used, by implementing its single public object GetFormat(Type) method, when there is a need to implement custom formatting of data like String and DateTime.
The public object GetFormat(Type) method simply returns an object that in turns is available to supply all available information to continue the formatting process. The Type passed in by the Framework is meant to give the implementor a way to decide which type to return back. Its like a Factory Method Design Pattern where the "formatType" is the type expected to be returned.
The code below was retrieved by .NET Reflector:
The code below was retrieved by .NET Reflector:
In my next Post will deal with an interesting behavior of DateTime.ParseExact that can cause some unexpected errors in production environment.
IFormatProvider is a .NET Framework Interface that should be used, by implementing its single public object GetFormat(Type) method, when there is a need to implement custom formatting of data like String and DateTime.
The public object GetFormat(Type) method simply returns an object that in turns is available to supply all available information to continue the formatting process. The Type passed in by the Framework is meant to give the implementor a way to decide which type to return back. Its like a Factory Method Design Pattern where the "formatType" is the type expected to be returned.
class MyProvider : IFormatProvider { public object GetFormat(Type formatType) { object result = null; //* Factory Method if (formatType == typeof( ICustomFormatter)) //* Some object, will be discussed later result = new object(); else //* Some object, will be discussed later result = new object(); return result; } }ICustomFormatter interface includes a single method, ICustomFormatter.Format. When the interface is implemented the 'Format' method must be implemented in order to return a custom-formatted string representation of an object's value. Usually, ICustomFormatter interface is used in conjunction with the IFormatProvider interface to customize the formating behavior of .NET Framework string formatting.
Strings
In some .NET implementations like String.Format(IFormatProvider provider, string format, params object[] args) the returned object of the public object GetFormat(Type) method is cast to ICustomFormatter and it's 'Format' method is called to actually perform the final formatting.The code below was retrieved by .NET Reflector:
public StringBuilder AppendFormat(IFormatProvider provider, string format, params object[] args) { if ((format == null) || (args == null)) { throw new ArgumentNullException((format == null) ? "format" : "args"); } int num = 0; int length = format.Length; char ch = '\0'; ICustomFormatter formatter = null; if (provider != null) { formatter = (ICustomFormatter)provider.GetFormat(typeof(ICustomFormatter)); } . . . }A simple implementation of both the Interfaces can be the following:
void Main() { string tamplate = "Hello {0:d}"; string name = "Gabi"; //* Calls internally MyProvider & Cast to ICustomFormatter string custumeFormattedString = string.Format( new MyProvider(), tamplate, name); Console.WriteLine( "StringFormatting: " + custumeFormattedString); } class MyProvider : IFormatProvider , ICustomFormatter { public object GetFormat(Type formatType) { object result = null; //* Factory Method if (formatType == typeof( ICustomFormatter)) result = new object(); //* Some object, will be discussed later else result = new object(); //* Some object, will be discussed later //* Must return an ICustomFormatter. In this case returns itself but can return any other ICustomFormatter return this; } public string Format( string format, object arg, IFormatProvider formatProvider) { //* format: 'd' , arg: 'gabi' , formatProvider: MyProvider string dateTime = //* Some logic return dateTime; } }
DateTime
In other implementations, like DateTime.ParseExact .NET doesn't try to cast the returned result from IFormatProvider to ICustomFormatter. Instead it aspects to receive an object to resolve the Culture in which the DateTime should be converted. In case that the object is not of CultureInfo or DateTimeFormatInfo type it will return the current Thread CultureInfo. NOTE: CultureInfo implements IFormatProvider.The code below was retrieved by .NET Reflector:
public static DateTimeFormatInfo GetInstance(IFormatProvider provider) { CultureInfo info2 = provider as CultureInfo ; if ((info2 != null) && !info2.m_isInherited) { return info2.DateTimeFormat; } DateTimeFormatInfo format = provider as DateTimeFormatInfo ; if (format != null) { return format; } if (provider != null) { format = provider.GetFormat(typeof( DateTimeFormatInfo)) as DateTimeFormatInfo; if (format != null) { return format; } } return CurrentInfo; }In other words, when using DateTime.ParseExact method the IFormatProvider parameter is null or not of type CultureInfo/DateTimeFormatInfo the frame work will behave the same, by returning the current CultureInfo object.
In my next Post will deal with an interesting behavior of DateTime.ParseExact that can cause some unexpected errors in production environment.
Comments
object result = null;
//* Factory Method
if (formatType == typeof( ICustomFormatter))
result = new object(); //* Some object, will be discussed later
else
result = new object(); //* Some object, will be discussed later
//* Must return an ICustomFormatter. In this case returns itself but can return any other ICustomFormatter
return this;