Extendable format provider I needed a better string formatting options like ToUpper and ToLower but I also wanted to be able to use the default formattings so I created a custom formatter. It's main purpose is to support a template engine where the user should be able to use different formattings like upper or lower case. I still however couldn't figure out how to be make the date time upper case.

public class ExtendableFormatter : IFormatProvider, ICustomFormatter
{
    public IDictionary&lt;Type, IFormatProvider&gt; FormatProviders { get; set; }

    public ExtendableFormatter()
    {
        FormatProviders = new Dictionary&lt;Type, IFormatProvider&gt;
        {
            { typeof(Byte), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(SByte), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(Int16), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(Int32), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(Int64), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(UInt16), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(UInt32), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(UInt64), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(Single), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(Double), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(Decimal), CultureInfo.InvariantCulture.NumberFormat },
            { typeof(DateTime), CultureInfo.InvariantCulture.DateTimeFormat },
            { typeof(String), new StringCaseFormatter() }
        };
    }

    public object GetFormat(Type formatType)
    {
        return formatType == typeof(ICustomFormatter) ? this : null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        var fp = (IFormatProvider)null;
        if (FormatProviders.TryGetValue(arg.GetType(), out fp))
        {
            formatProvider = fp;
        }

        format = string.IsNullOrEmpty(format) ? string.Empty : ":" + format;
        var result = string.Format(formatProvider, "{0" + format + "}", arg);
        return result;
    }

}

public class StringCaseFormatter : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        return formatType == typeof(ICustomFormatter) ? this : null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        switch (format)
        {
            case "U": return arg.ToString().ToUpper();
            case "L": return arg.ToString().ToLower();
            default: return arg.ToString();
        }
    }
}


Example:

string.Format(
    new ExtendableFormatter(),
    "foo {0:U} baz {1,-5:f1} {2:ddMMMyy}",
    "qux", 1.234f, DateTime.Now).Dump();


Result:


  foo QUX baz 1.2   05Jun16
public IDictionary&lt;Type, IFormatProvider&gt; FormatProviders { get; set; }  



This is bad. Having a public setter for the dictionary will let a user of that code pass in null resulting in the Format() method throwing a NullReferenceException.  



You don't check the passed in parameters of the Format() method if they are valid. By omiting the validation of the arguments you are exposing implementation details for the case they aren't valid. E.g if the passed object arg is null then the call to arg.GetType() will throw and exposes that you are requesting the type of that object.  

You only want to show the user that the passed in arguments are invalid, but you shouldn't let the code do it for you.