首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

C# IFormatProvider 與 ICustomFormatter 實現自定義格式化完整指南

     編輯:Java 相關知識

背景

.NET 格式化系統允許開發者通過實現 IFormatProvider 和 ICustomFormatter 定義專屬格式字符串(如 {0:MyFormat}),實現業務專屬的輸出格式。

核心接口解析

IFormatProvider

提供格式化服務的工廠,單一方法:

object GetFormat(Type formatType);
  • 參數 formatType:請求的格式化器類型(通常是 typeof(ICustomFormatter))
  • 返回:實現該類型的對象,或 null 表示不支持

ICustomFormatter

實際執行格式化,單一方法:

string Format(string format, object arg, IFormatProvider formatProvider);
  • format:格式字符串(冒號後內容,如 "MyFormat")
  • arg:待格式化的對象
  • formatProvider:格式化提供者(可遞歸調用)
  • 返回:格式化後的字符串

完整實現示例

public class MyFormatter : ICustomFormatter, IFormatProvider {
    // IFormatProvider:被請求時返回自己(如果是 ICustomFormatter)
    public object GetFormat(Type formatType) {
        return formatType == typeof(ICustomFormatter) ? this : null;
    }

    // ICustomFormatter:核心格式化邏輯
    public string Format(string format, object arg, IFormatProvider provider) {
        // 1. 無自定義格式 → 走標準格式化
        if (string.IsNullOrEmpty(format)) {
            return arg is IFormattable 
                ? ((IFormattable)arg).ToString(null, provider) 
                : arg.ToString();
        }

        // 2. 識別自定義格式字符串
        if (format == "MyFormatter") {
            return "**" + arg.ToString(); // 業務邏輯:前綴 **
        }

        // 3. 其他格式 → 委託標準格式化
        return arg is IFormattable 
            ? ((IFormattable)arg).ToString(format, provider) 
            : arg.ToString();
    }
}

調用鏈路深度解析

int i = 100;
MyFormatter fmt = new MyFormatter();

// 三種調用方式
string s1 = string.Format(fmt, "{0}", i);        // 無格式 → "100"
string s2 = string.Format(fmt, "{0:C}", i);      // 標準貨幣 → "¥100.00"
string s3 = string.Format(fmt, "{0:MyFormatter}", i); // 自定義 → "**100"

內部執行流程

  1. string.Format(provider, format, args) 接收 MyFormatter 作為 provider
  2. 內部 StringBuilder.AppendFormat 解析格式字符串
  3. 遇到 {0:MyFormatter},調用 provider.GetFormat(typeof(ICustomFormatter))
  4. 得到 MyFormatter 實例,調用其 Format("MyFormatter", 100, provider)
  5. 返回 "**100",拼接進最終字符串

進階場景與最佳實踐

1. 支持多種自定義格式

if (format == "HEX") return "0x" + ((int)arg).ToString("X");
if (format == "BIN") return "0b" + Convert.ToString((int)arg, 2);

2. 格式化複雜對象

if (arg is User u && format == "SHORT") 
    return $"{u.Name}({u.Id})";

3. 線程安全與性能

  • IFormatProvider 實例通常無狀態,可單例複用
  • 避免在 Format 中做重 IO/計算,必要時緩存

4. 結合 ToString() 擴展

public class User : IFormattable {
    public string ToString(string format, IFormatProvider provider) {
        if (provider is MyFormatter) 
            return ((MyFormatter)provider).Format(format, this, provider);
        return base.ToString();
    }
}

常見坑與調試技巧

問題原因解決
自定義格式不生效GetFormat 返回 null 或類型不匹配確保返回 this 且參數為 typeof(ICustomFormatter)
遞歸調用導致棧溢出Format 中又調用 string.Format 且未終止條件非自定義格式直接委託 arg.ToString(format, provider)
數值類型格式化異常arg 為值類型,boxing/unboxing 開銷用泛型或模式匹配優化

總結

IFormatProvider 是「工廠」,ICustomFormatter 是「工人」。兩者合一實現自定義格式化:GetFormat 識別身份,Format 實現邏輯。掌握調用鏈路 string.Format → AppendFormat → GetFormat → Format,即可為任何類型注入業務專屬格式語義,極大提升代碼表達力與可讀性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved