public sealed class CustomApiVersionFormatter : IFormatProvider, ICustomFormatter { private static CustomApiVersionFormatter? instance; public static CustomApiVersionFormatter GetInstance( IFormatProvider? formatProvider ) { if ( formatProvider is CustomApiVersionFormatter provider ) { return provider; } if ( formatProvider?.GetFormat( typeof( CustomApiVersionFormatter ) ) is CustomApiVersionFormatter customProvider ) { return customProvider; } return instance ??= new(); } public string Format( string? format, object? arg, IFormatProvider? formatProvider ) { if ( arg is not CustomApiVersion value ) { return GetDefaultFormat( format, arg, formatProvider ); } // TODO: very naive custom formatting. tokenizer is typically needed here to // break apart constituent pieces, format codes, format options, and embedded literals. var formatAll = string.IsNullOrEmpty( format ) || format.Length > 1; var text = new StringBuilder(); if ( formatAll ) { text.Append( value.Token1 ).Append( '.' ).Append( value.Token2 ); if ( !string.IsNullOrEmpty( value.Token3 ) ) { text.Append( '.' ).Append( value.Token3 ); } } else { switch ( format[0] ) { case 'A': text.Append( value.Token1 ); break; case 'B': text.Append( value.Token2 ); break; case 'C': text.Append( value.Token1 ); break; } } return text.ToString(); } public object? GetFormat( Type? formatType ) { if ( typeof( ICustomFormatter ).Equals( formatType ) ) { return this; } if ( formatType != null && GetType().GetTypeInfo().IsAssignableFrom( formatType.GetTypeInfo() ) ) { return this; } return null; } private static string GetDefaultFormat( string? format, object? arg, IFormatProvider? formatProvider ) { if ( arg == null ) { return format ?? string.Empty; } if ( !string.IsNullOrEmpty( format ) && arg is IFormattable formattable ) { return formattable.ToString( format, formatProvider ); } return arg.ToString() ?? string.Empty; } }