Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
506 views
in Technique[技术] by (71.8m points)

formatting - C#: Connection between IFormattable, IFormatProvider and ICustomFormatter, and when to use what

What are the difference and connection between IFormattable, IFormatProvider and ICustomFormatter and when would they be used? A simple implementation example would be very nice too.

And I don't really mean when it is used in the .net framework, but when I would implement these myself and in that case what classes would typically implement what interface and how to do it properly.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
  • IFormattable is an object which supports formats in string.Format, i.e. the xxx in {0:xxx}. string.Format will delegate to an object's IFormattable.ToString method if the object supports the interface.

  • IFormatProvider is a source of configuration information that formatters use for things like culture-specific date and currency layout.

  • However, for situations like e.g. DateTime, where the instance you want to format already implements IFormattable yet you don't control the implementation (DateTime is supplied in the BCL, you can't replace it easily), there is a mechanism to prevent string.Format from simply using IFormattable.ToString. Instead, you implement IFormatProvider, and when asked for an ICustomFormatter implementation, return one. string.Format checks the provider for an ICustomFormatter before it delegates to the object's IFormattable.Format, which would in turn likely ask the IFormatProvider for culture-specific data like CultureInfo.

Here is a program which shows what string.Format asks the IFormatProvider for, and how the flow of control goes:

using System;
using System.Globalization;

class MyCustomObject : IFormattable
{
    public string ToString(string format, IFormatProvider provider)
    {
        Console.WriteLine("ToString("{0}", provider) called", format);
        return "arbitrary value";
    }
}

class MyFormatProvider : IFormatProvider
{
    public object GetFormat(Type formatType)
    {
        Console.WriteLine("Asked for {0}", formatType);
        return CultureInfo.CurrentCulture.GetFormat(formatType);
    }
}

class App
{
    static void Main()
    {
        Console.WriteLine(
            string.Format(new MyFormatProvider(), "{0:foobar}", 
                new MyCustomObject()));
    }
}

It prints this:

Asked for System.ICustomFormatter
ToString("foobar", provider) called
arbitrary value

If the format provider is changed to return a custom formatter, it takes over:

class MyFormatProvider : IFormatProvider
{
    public object GetFormat(Type formatType)
    {
        Console.WriteLine("Asked for {0}", formatType);
        if (formatType == typeof(ICustomFormatter))
            return new MyCustomFormatter();
        return CultureInfo.CurrentCulture.GetFormat(formatType);
    }
}

class MyCustomFormatter : ICustomFormatter
{
    public string Format(string format, object arg, IFormatProvider provider)
    {
        return string.Format("(format was "{0}")", format);
    }
}

When run:

Asked for System.ICustomFormatter
(format was "foobar")

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...