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

Nancy Garero 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.
KoRnFan said…
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

GetHashCode Hands-On Session

The following is a hands-on post meant to demonstrate how GetHashCode() and Equals() methods are used by .NET Framework under the hood. For the sake of simplicity I will refer to the popular hashed-base Dictionary type, although any other hash based structure will follow a similar behavior, if not the same one. After understanding this post you should be able to spot potential problematic behaviors and resolve them, prevent creation of unreachable items in dictionaries and improve CRUD actions performance on hash based structures. The TheoryGetHashCode() is used to create a unique integer identifier for objects/structs. The hashcode can be used for two purposes: Programmatically, by developers, to distinguish objects/structs form each other (NOTE: Not recommended when the default .NET implementation is used, as it's not guaranteed to preserve the same hash between .NET versions and platforms)Internally, by .NET Framework, when using the object/struct as a key in a hashed based l…

Closures in C# vs JavaScript -
Same But Different

Closure in a Nutshell Closures are a Software phenomenon which exist in several languages, in which methods declared inside other methods (nested methods), capture variables declared inside the outer methods. This behavior makes captured variables available even after the outer method's scope has vanished.

The following pseudo-code demonstrates the simplest sample:
Main() //* Program starts from here { Closures(); } AgeCalculator() { int myAge = 30; return() => { //* Returns the correct answer although AgeCalculator method Scope should have ordinarily disappear return myAge++; }; } Closures() { Func ageCalculator = AgeCalculator(); //* At this point AgeCalculator scopeid cleared, but the captured values keeps to live Log(ageCalculator()); //* Result: 30 Log(ageCalculator()); //* Result: 31 } JavaScript and C# are two languages that support…

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 debuggerJava Debug Interface (JDI) - Defines a high-level Java API designed to facilitate the interaction between debugge and debuggers. Internally J…