.NET Framework 中的格式化類型簡述

 

講白了就是說,「值」可以用何種樣式來表現出來。

 

一、ToString方法

每個衍生自 System.Object 的類型都會自動繼承無參數的 ToString 方法,

這個方法預設會傳回類型的名稱(包含命名空間,如果有的話)。

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Automobile firstAuto = new Automobile();
            Console.WriteLine(firstAuto.ToString());
            Console.ReadKey();
        }
    }

    public class Automobile
    {
        // No implementation. All members are inherited from Object.
    }
}

額外一提的是

Console.WriteLine(firstAuto);

WriteLine方法也隱含著傳回類型的名稱

// Writes the text representation of an object followed by a line
// terminator to the text stream.
//
public virtual void WriteLine(Object value) {
    if (value==null) {
        WriteLine();
    }
    else {
        // Call WriteLine(value.ToString), not Write(Object), WriteLine().
        // This makes calls to WriteLine(Object) atomic.
        IFormattable f = value as IFormattable;
        if (f != null)
            WriteLine(f.ToString(null, FormatProvider));
        else
            WriteLine(value.ToString());
    }
}

而物件的ToString方法內部為

public class Object
{
    // Returns a String which represents the object instance.  The default
    // for an object is to return the fully qualified name of the class.
    // 
    public virtual String ToString()
    {
        return GetType().ToString();
    }
}

 

二、利用ToString方法來解說「值」如何以何種樣式來表現出來。

(1)、以數值int型別作為例子,我們想要將數值「零」個別用貨幣、百比來表示

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 0;
            Console.WriteLine(a.ToString("C"));
            Console.WriteLine(a.ToString("P"));
            Console.ReadKey();
        }
    }
}

結果為

為何用代號"C"與"P"就可以呈現不同樣式,請參考標準數值格式字串簡述

自訂數值格式字串簡述標準日期和時間格式字串簡述自訂日期和時間格式字串簡述

複合格式簡述

 

我更有興趣去了解深入的實作方式,

會發現int型別的ToString有四種多載方法

public override string ToString();
public string ToString(IFormatProvider provider);
public string ToString(string format);
public string ToString(string format, IFormatProvider provider);

只列後面兩實作方法,

public String ToString(String format) {
    Contract.Ensures(Contract.Result<String>() != null);
    return Number.FormatInt32(m_value, format, NumberFormatInfo.CurrentInfo);
}
public String ToString(String format, IFormatProvider provider) {
    Contract.Ensures(Contract.Result<String>() != null);
    return Number.FormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
}

會發現其核心是由NumberFormatInfo物件中的屬性值來決定數值的字串表現樣式,

那IFormatProvider型別跟NumberFormatInfo靜態物件是什麼關係?

你可以想像IFormatProvider就像是條件清單一樣一一列出(註一),

然後將IFormatProvider型別的物件傳遞給NumberFormatInfo物件要他根據清單上的條件把字串指定樣式給表現出來。

 

註一:IFormatProvider只是個介面而已,將由CultureInfo類別會繼承IFormatProvider並實作他。

using System;
using System.Globalization;

public class Example
{
    public static void Main()
    {
        decimal value = 1603.42m;
        Console.WriteLine(value.ToString("C3", new CultureInfo("en-US")));
        Console.WriteLine(value.ToString("C3", new CultureInfo("fr-FR")));
        Console.WriteLine(value.ToString("C3", new CultureInfo("de-DE")));
        Console.ReadKey();
    }
}

 

(2)、以時間DateTime型別作為例子,我們想要將時間用多種樣式來表示

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime date1 = new DateTime(2016, 11, 5, 13, 30, 20);

            Console.WriteLine(date1.ToString("D"));
            Console.WriteLine(date1.ToString("d"));
            Console.WriteLine(date1.ToString("F"));
            Console.WriteLine(date1.ToString("f"));
            Console.ReadKey();
        }
    }
}

執行畫面為

 

去了解深入的實作方式,也是一樣會發現DateTime型別的ToString有四種多載方法

public override string ToString();
public string ToString(IFormatProvider provider);
public string ToString(string format);
public string ToString(string format, IFormatProvider provider);

也是一樣只列後面兩實作方法,

public String ToString(String format) {
    Contract.Ensures(Contract.Result<String>() != null);
    return DateTimeFormat.Format(this, format, DateTimeFormatInfo.CurrentInfo);
}
public String ToString(String format, IFormatProvider provider) {
    Contract.Ensures(Contract.Result<String>() != null);
    return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider));
}

我們會發現時間型別的ToString實作方法跟數值型別的ToString實作方法有一些出入,

其實作方法差別在一個核心是由DateTimeFormatInfo物件中的屬性值來決定時間的字串表現樣式,

另一個核心是由NumberFormatInfo物件中的屬性值來決定數值的字串表現樣式。

 

參考資料:

.NET Framework 中的格式化類型

String.Format 方法