Using IFormattable to make your output more convenient







  1. Module Module1
  2.     Sub Main()
  3.         Dim Microsoft_example_about_Account_Number As New Account_Number(34567)
  4.         Dim Microsoft_example_about_Tempture As New Temperature(333)

  5.         Dim formatProvider() As FormatProvider_class = {
  6.                     New FormatProvider_class(New Globalization.CultureInfo("de-DE")),
  7.                     New FormatProvider_class(New Globalization.CultureInfo("fr-FR"))
  8.                 }
  9.         Dim fmt = "{0:H}" & vbNewLine &
  10.                   "{1:E}" & vbNewLine &
  11.                   "{2:G}" & vbNewLine &
  12.                   "{3:G}" & vbNewLine &
  13.                   "{4:G}" & vbNewLine &
  14.                   "{5:F}" & vbNewLine
  15.         For Each fmtProvider As FormatProvider_class In formatProvider
  16.             Console.WriteLine("==========" & fmtProvider.CultureInfo.Name & "============")
  17.             Console.WriteLine(String.Format(fmtProvider, fmt,
  18.                    Microsoft_example_about_Account_Number,
  19.                    123.45,
  20.                    #2024/03/12 12:03:24#,
  21.                    New TimeSpan(12345678),
  22.                    DayOfWeek.Friday,
  23.                    Microsoft_example_about_Tempture))
  24.         Next
  25.         Console.WriteLine($" 
  26.                {Microsoft_example_about_Account_Number:H} 
  27.                {123.45:E}
  28.                {#2024/03/12 12:03:24#}
  29.                {New TimeSpan(12345678)}
  30.                {DayOfWeek.Friday:G}
  31.                {Microsoft_example_about_Tempture:F}
  32.                ")
  33.         Console.ReadKey()
  34.         Console.WriteLine($"{New CultureInfomation_on_Windows():C}") : Console.ReadKey()
  35.         BrowseHtml.Show($"{New CultureInfomation_on_Windows():W}")
  36.     End Sub
  37.     Class BrowseHtml
  38.             Class Register_RunTime_data
  39.                 Sub New(Optional OldFilePath As Boolean = True)
  40.                     If OldFilePath Then GetHtmlFilePath()
  41.                     If String.IsNullOrEmpty(HtmlFilePath) Then
  42.                         HtmlFilePath = IO.Path.ChangeExtension(HtmlFilePath2, "html")
  43.                     End If
  44.                 End Sub
  45.                 Protected Overrides Sub finalize()
  46.                     SaveHtmlFilePath()
  47.                 End Sub
  48.                 Const Myblog = "MyBlog_7", Key = "TempFile"
  49.                 Public Shared Sub SaveHtmlFilePath()
  50.                     Interaction.SaveSetting(Reflection.Assembly.GetExecutingAssembly.GetName.Name,
  51.                        Myblog, Key, HtmlFilePath)
  52.                 End Sub
  53.                 Public Shared Sub GetHtmlFilePath()
  54.                     Try
  55.                         HtmlFilePath =
  56.                         Interaction.GetSetting(Reflection.Assembly.GetExecutingAssembly.GetName.Name,
  57.                         Myblog, Key)
  58.                     Catch ex As Exception

  59.                     End Try
  60.                 End Sub
  61.             End Class
  62.             Public Shared msedge_exe As String =
  63.             IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
  64.                          "Microsoft\Edge\Application\msedge.exe")
  65.             Public Shared HtmlFilePath1 As String = IO.Path.GetTempFileName
  66.             Public Shared HtmlFilePath2 As String = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
  67.                                          IO.Path.GetRandomFileName)
  68.             Shared HtmlFilePath As String
  69.             Public Shared Sub Show(Html_content As String)
  70.             Static For_HtmlFilePath As New Register_RunTime_data()
  71.             Using HtmlFile As New IO.StreamWriter(HtmlFilePath, False, Text.Encoding.UTF8),
  72.                       BrowserProcess As New Process
  73.                     HtmlFile.Write(Html_content)
  74.                     HtmlFile.Flush()

  75.                     BrowserProcess.StartInfo = New ProcessStartInfo(HtmlFilePath) With {
  76.                       .Verb = "open",
  77.                       .UseShellExecute = True
  78.                     }
  79.                     If Not BrowserProcess.Start() Then Throw New Exception("error in BrowserProcess")
  80.                 End Using
  81.             End Sub
  82.         End Class

  83. '#Const trace_it = True
  84.     Class FormatProvider_class
  85.             Implements IFormatProvider, ICustomFormatter
  86.             Public CultureInfo As Globalization.CultureInfo
  87.             Sub New(cultureinfo As Globalization.CultureInfo)
  88.                 If cultureinfo Is Nothing Then
  89.                     Me.CultureInfo = Globalization.CultureInfo.CurrentCulture
  90.                 Else
  91.                     Me.CultureInfo = cultureinfo
  92.                 End If
  93.                 Trace_string = New Text.StringBuilder
  94.             End Sub
  95.             Function GetFormat(FormatType As Type) As Object Implements IFormatProvider.GetFormat
  96.                 Trace_string.Append(
  97.                     $"(IFormatProvider.GetFormat) FormatType={FormatType} CultureName={CultureInfo.Name}")
  98.                 Try
  99.                     Select Case FormatType
  100.                         Case GetType(ICustomFormatter)
  101.                             Return Me
  102.                         Case GetType(Globalization.NumberFormatInfo)
  103.                             Trace_string.Append($"Use NumberFormatInfo to parse/format")
  104.                             Return CultureInfo.NumberFormat
  105.                         Case GetType(Globalization.DateTimeFormatInfo)
  106.                             Trace_string.Append($"Use DateTimeFormat to parse/format")
  107.                             Return CultureInfo.DateTimeFormat
  108.                         Case Else
  109.                             Return Nothing
  110.                     End Select
  111.                 Catch ex As Exception
  112.                     Return Nothing
  113.                 Finally
  114. #If TRACE = trace_it Then
  115.                 Console.WriteLine(Trace_string) : Trace_string.Clear()
  116. #End If
  117.                 End Try
  118.             End Function
  119.             Public Function Format(fmt As String, arg As Object, formatProvider As IFormatProvider) As String _
  120.                      Implements ICustomFormatter.Format
  121.                 Trace_string.Append($"(ICustomFormatter.Format__IN){arg.GetType.Name,15} ")
  122.                 Try
  123.                     Select Case arg.GetType()
  124.                         Case GetType(Account_Number)
  125.                         Case GetType(Temperature)
  126.                         Case Else
  127.                     End Select
  128.                     Return CType(arg, IFormattable).ToString(fmt, Me.CultureInfo)
  129.                 Finally
  130.                     Trace_string.Append("(ICustomFormatter.Format__OUT)")
  131. #If TRACE = trace_it Then
  132.                 Console.WriteLine(Trace_string) : Trace_string.Clear()
  133. #End If
  134.                 End Try
  135.             End Function
  136.             Dim Trace_string As Text.StringBuilder
  137.         End Class
  138.         Structure Account_Number
  139.             Implements IFormattable
  140.             Public value As Long
  141.             Public Sub New(value As Long)
  142.                 Me.value = value
  143.             End Sub
  144.             Public Overrides Function ToString() As String
  145.                 Return Me.ToString("H", Globalization.CultureInfo.CurrentCulture)
  146.             End Function
  147.             Public Overloads Function ToString(fmt As String) As String
  148.                 Return ToString(fmt, Globalization.CultureInfo.CurrentCulture)
  149.             End Function
  150.             Const ACCT_LENGTH = 12I

  151.             Public Overloads Function ToString(fmt As String, provider As IFormatProvider) _
  152.                   As String Implements IFormattable.ToString
  153. #If TRACE = trace_it Then
  154.             If provider Is Nothing Then Console.WriteLine($"fmt=({fmt})   Nothing <------------- provider")
  155. #End If
  156.             Dim Bool_fmt As Boolean = fmt = "I" OrElse fmt = "H"
  157.                 If Not Bool_fmt Then Return value.ToString() & "  <----- format specifier not supported"
  158.                 ' Convert argument to a string.
  159.                 Dim result As String = value.ToString()

  160.                 ' If account number is less than 12 characters, pad with leading zeroes.
  161.                 If result.Length < ACCT_LENGTH Then result = result.PadLeft(ACCT_LENGTH, "0"c)
  162.                 ' If account number is more than 12 characters, truncate to 12 characters.
  163.                 If result.Length > ACCT_LENGTH Then result = Left(result, ACCT_LENGTH)
  164.                 If fmt = "I" Then                    ' Integer-only format.
  165.                     Return result
  166.                     ' Add hyphens for H format specifier.
  167.                 ElseIf fmt = "H" Then                                 ' Hypenated format.
  168.                     Return Left(result, 5) & "-" & Mid(result, 6, 3) & "-" & Right(result, 4)
  169.                 End If
  170.                 Return result
  171.             End Function
  172.         End Structure

  173.         Public Const Celsius_Str = " °C"
  174.         Public Const Fahrenheit_Str = " °F"
  175.         Public Const Kelvin_Str = " K"

  176.         Public Class Temperature
  177.             Implements IFormattable
  178.             Protected temp As Decimal
  179.             Public Sub New(Temperature As Decimal)
  180.                 If Temperature < -273.15R Then
  181.                     Throw New Exception($"{Temperature} is less than absolute zero.")
  182.                 End If
  183.                 Me.temp = Temperature
  184.             End Sub
  185.             Public ReadOnly Property Celsius As Decimal
  186.                 Get
  187.                     Return temp
  188.                 End Get
  189.             End Property
  190.             Public ReadOnly Property Fahrenheit As Decimal
  191.                 Get
  192.                     Return temp * 9 / 5 + 32
  193.                 End Get
  194.             End Property
  195.             Public ReadOnly Property Kelvin As Decimal
  196.                 Get
  197.                     Return temp + 273.15D
  198.                 End Get
  199.             End Property
  200.             Public Overrides Function ToString() As String
  201.                 Return Me.ToString("G", Globalization.CultureInfo.CurrentCulture)
  202.             End Function

  203.             Public Overloads Function ToString(format As String) As String
  204.                 Return Me.ToString(format, Globalization.CultureInfo.CurrentCulture)
  205.             End Function
  206.             Public Overloads Function ToString(Format As String, provider As IFormatProvider) _
  207.                As String Implements IFormattable.ToString
  208.                 If (String.IsNullOrEmpty(Format)) Then Format = "G"
  209.                 If (provider Is Nothing) Then provider = Globalization.CultureInfo.CurrentCulture

  210.                 Select Case (Format.ToUpperInvariant())
  211.                     Case "G", "C"
  212.                         Return Celsius.ToString("F2", provider) + Celsius_Str
  213.                     Case "F"
  214.                         Return Fahrenheit.ToString("F2", provider) + Fahrenheit_Str
  215.                     Case "K"
  216.                         Return Kelvin.ToString("F2", provider) + Kelvin_Str
  217.                     Case Else
  218.                         Throw New FormatException($"The {Format} format string is not supported.")
  219.                 End Select
  220.             End Function

  221.         End Class

  222.     End Module
  223.     Public Class CultureInfomation_on_Windows
  224.         Implements IFormattable
  225.         Protected Cultures As Globalization.CultureInfo()
  226.         Public Sub New()
  227.             Me.Cultures = Globalization.CultureInfo.GetCultures(Globalization.CultureTypes.AllCultures)
  228.         End Sub
  229.         Public Overrides Function ToString() As String
  230.             Return Me.ToString("G", Globalization.CultureInfo.CurrentCulture)
  231.         End Function
  232.         Public Overloads Function ToString(Format As String, provider As IFormatProvider) _
  233.                As String Implements IFormattable.ToString
  234.             If (String.IsNullOrEmpty(Format)) Then Format = "G"
  235.             If (provider Is Nothing) Then provider = Globalization.CultureInfo.CurrentCulture

  236.             Select Case (Format.ToUpperInvariant())
  237.                 Case "G", "W"
  238.                     Dim Html_Str As New Text.StringBuilder("<!DOCTYPE html>
  239. <html dir=""ltr"" , lang=""zh-tw"">
  240. <head>
  241.     <meta charset=""utf-8"" />
  242.     <title>Cultures information on Windows</title>
  243. </head>
  244. <body>
  245.   <table>
  246.         <colgroup>
  247.             <col />
  248.             <col style=""background-color:chartreuse"" />
  249.             <col />
  250.             <col style=""background-color:chartreuse"" />
  251.             <col />
  252.             <col style=""background-color:chartreuse"" />
  253.             <col />
  254.             <col style=""background-color:chartreuse"" />
  255.         </colgroup>
  256.   <tr><th>index</th><th>LCID</th><th>Name</th><th>NativeName</th><th>IsNeutral</th><th>EnglishName</th></tr>
  257. ")

  258.                     Dim index As Int32 = 0
  259.                     For Each culture As Globalization.CultureInfo In Cultures
  260.                         index += 1
  261.                         Html_Str.Append(
  262.     $"<tr><td>{index}</td>
  263.       <td>{culture.LCID}</td>
  264.       <td>{culture.Name}</td>
  265.       <td>{culture.NativeName}</td>
  266.       <td>{culture.IsNeutralCulture}</td>
  267.       <td>{culture.EnglishName}</td>
  268.   </tr>")
  269.                     Next
  270.                     Html_Str.Append("</table></body></html>")
  271.                     Return Html_Str.ToString
  272.                 Case "C"
  273.                     Dim Console_Str As New Text.StringBuilder()
  274.                     Console_Str.AppendLine("index  LCID           Name" &
  275.                       "                                         NativeName  NeutralCulture")

  276.                     Dim index As Int32 = 0
  277.                     For Each culture As Globalization.CultureInfo In Cultures
  278.                         index += 1
  279.                         Dim NativeName As String = culture.NativeName
  280.                         Console_Str.AppendLine(
  281.                        $"{index,5} {culture.LCID,5} {culture.Name,14} {NativeName,50} {culture.IsNeutralCulture,6}")
  282.                     Next
  283.                     Return Console_Str.ToString
  284.                 Case Else
  285.                     Throw New FormatException($"The {Format} format string is not supported.")
  286.             End Select
  287.         End Function
  288.     End Class
                  IFormatProvider Interface

留言

這個網誌中的熱門文章

Marshalling

Calling a C# WPF library from C++

Marshalling II