Skip to main content

Formatting Data with IFormatProvider & ICustomFormatter

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.
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

Anonymous said…
We should need an expert for understanding the hierarchy and function of the big data for making any procedure for this. The data scientist helps us to understand the big data which have more complication and problems and we can get the best data scientist form here at Active Wizards.
I didn't understand why in your example you return this instead result?

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;

The Best

From Layers to Microunits

The evolution of “Code Cohesion” and “Separation of Concerns” The software industry has recognized the values of “Separation of Concerns” and “Code Cohesion” for more than two decades. Many articles, books and software-thinkers have contributed methodologies to implement these important values. In this short article I’d like to compare the conservative “Layers” solution with a new approach, which I call “Microunits”, that can open new ways of solving software design challenges. Read more...

Rendering Dynamically JavaScript Files from Server Side Code

Today's RIA applications require us to build robots apps with minimal post-backs cycles, this requirement forces us to make an extensive use of JavaScript and technologies as AJAX. Today I want to blog about "Rendering Dynamically JavaScript Files from Server Side Code", this is a very useful and elegant (and strangely not discussed enough) technique that can improve our RIA application architecture. Good But Not Perfect So let's try to describe a small task and it's solution to make a good picture about this strong technique. You work on a "Rental Car" application that is in charge of keeping track of all rented cars and sends an email notification to the "Rental Car" company manager about cars that their rental period already exceeded. As mentioned before, your app makes an extensive use of JavaScript and AJAX in order to improve users experience. Now, let's also say that you need to read the SMTP configuration parameters, such ...

Method Breakpoints are Evil

Some IDEs expose an option to set "Method Breakpoints", it turns out that "Method Breakpoints" might tremendously decrease debugger's performance. In this article, I explain what are "Method Breakpoints" and the reasons they impact performance so badly. To better understand this subject I will cover how Debuggers works under the hoods and how Breakpoints and Method Breakpoints are implemented internally. Java Platform Debugger Architecture JDPA is an architecture designed for enabling communication between debuggers and debugees. The architecture consists of three APIs: JVM Tool Interface (JVM TI) - A native interface which defines the services a VM must provide for debugging purposes Java Debug Wire Protocol (JWDP) - A textual API which defines the communication's protocol between debugee and debugger Java Debug Interface (JDI) - Defines a high-level Java API designed to facilitate the interaction between debugge and debuggers. ...