IFormattable

Shy·2025년 3월 17일

C#

목록 보기
19/27

IFormattable

IFormattable은 객체를 특정 형식(format)으로 변환할 수 있도록 하는 인터페이스다.

즉, ToString(string format, IFormatProvider formatProvider) 메서드를 구현해야 한다.

  • 형식 지정 가능: ToString() 메서드에 형식을 지정하여 다양한 포맷으로 변환할 수 있다.
  • 기본 제공 타입에도 구현되어 있음: int, double, DateTime 등 기본 타입들도 IFormattable을 구현하고 있다.
  • 제네릭 제약 조건으로 사용 가능: where T : IFormattable을 사용하여 특정 타입만 받도록 제한을 주는 것이 가능하다.
  • 직접 구현 가능: 사용자가 만든 클래스에서도 IFormattable을 구현하면, 형식 변환 기능을 커스터마이징할 수 있다.

또한, IFormattable인터페이스의 필수 구현 메서드는 다음과 같다.

public interface IFormattable
{
    string ToString(string format, IFormatProvider formatProvider);
}

// 이 메서드만 구현하면 IFormattable을 지원하는 클래스가 된다.

1. 기본 제공 타입(int, double, DateTime)의 IFormattable활용 예제

int number = 12345;
Console.WriteLine(number.ToString("N0")); // 12,345

double price = 123.456;
Console.WriteLine(price.ToString("F2")); // 123.46

DateTime now = DateTime.Now;
Console.WriteLine(now.ToString("yyyy-MM-dd")); // 2025-03-17 (예제 날짜)
  • int, double, DateTime 등은 이미 IFormattable을 구현하고 있어서 다양한 형식으로 출력이 가능하다.

왜 IFormatProvider를 명시적으로 넣지 않아도 작동할까?

위 예제에서 ToString("N0"), ToString("F2"), ToString("yyyy-MM-dd")을 호출할 때 IFormatProvider를 명시적으로 전달하지 않았는데도 잘 동작하는 이유는 기본적으로 .NETCultureInfo.CurrentCulture를 사용하기 때문이다.

System.Globalization.CultureInfo.CurrentCulture

  • CultureInfo.CurrentCulture는 현재 실행 중인 스레드의 문화권 정보를 나타낸다.
  • OS 설정에 따라 결정되며, 예를 들어 한국어 환경에서는 "ko-KR"이 기본값이다.

기본 ToString() 동작 흐름

public string ToString(string format)
{
    return ToString(format, CultureInfo.CurrentCulture);
}

즉, 우리가 ToString("N0")처럼 IFormatProvider 없이 호출하면, 내부적으로 자동으로 CultureInfo.CurrentCulture를 사용하게 된다.

아래 코드로 현재 문화권을 확인해 볼 수도 있다.

using System;
using System.Globalization;

class Program
{
    static void Main()
    {
        Console.WriteLine(CultureInfo.CurrentCulture.Name); // 현재 문화권 출력 (예: "ko-KR" or "en-US")
    }
}

2. 직접 IFormattable구현하기

사용자 정의 클래스 예제

using System;

public class Product : IFormattable
{
    public string Name { get; set; }
    public decimal Price { get; set; }

    // IFormattable 메서드 구현
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (string.IsNullOrEmpty(format)) format = "G"; // 기본 형식 General

        switch (format.ToUpper())
        {
            case "G": return $"{Name} - {Price:C}";  // 기본 형식 (통화 표기)
            case "N": return $"{Name} (Price: {Price:N2})";  // 숫자 형식 (소수점 2자리)
            case "P": return $"[{Name}] ${Price}";  // 간단한 출력
            default: throw new FormatException($"Invalid format '{format}'");
        }
    }

    public override string ToString() => ToString("G", null);
}
// 사용 예제
Product product = new Product { Name = "Laptop", Price = 1200.50m };

Console.WriteLine(product.ToString("G", null)); // Laptop - $1,200.50
Console.WriteLine(product.ToString("N", null)); // Laptop (Price: 1,200.50)
Console.WriteLine(product.ToString("P", null)); // [Laptop] $1200.50

// 기본 ToString() 호출
Console.WriteLine(product); // Laptop - $1,200.50
  • IFormattable을 직접 구현하면, 사용자 정의 형식으로 객체를 문자열로 변환 가능하다!

3. IFormattable을 제네릭 제약 조건으로 사용

public class Formatter<T> where T : IFormattable
{
    public void PrintFormatted(T value, string format)
    {
        Console.WriteLine(value.ToString(format, null));
    }
}
// 사용 예제
Formatter<int> intFormatter = new Formatter<int>();
intFormatter.PrintFormatted(12345, "N0"); // 12,345

Formatter<double> doubleFormatter = new Formatter<double>();
doubleFormatter.PrintFormatted(123.456, "F2"); // 123.46

Formatter<DateTime> dateFormatter = new Formatter<DateTime>();
dateFormatter.PrintFormatted(DateTime.Now, "yyyy-MM-dd"); // 2025-03-17
  • where T : IFormattable을 사용하면, 형식 변환이 가능한 타입만 받을 수 있도록 제한할 수 있다.

정리

개념설명
IFormattable 인터페이스형식 변환이 가능하도록 ToString(string format, IFormatProvider provider)을 요구
기본 구현 타입int, double, DateTime 등은 이미 IFormattable을 구현
사용자 정의 클래스 구현 가능IFormattable을 직접 구현하여 원하는 형식으로 문자열 변환 가능
제네릭 제약 조건where T : IFormattable을 사용하여 특정 타입만 받도록 제한 가능
컬렉션과 함께 사용where T : IEnumerable<IFormattable>을 사용하여 IFormattable을 구현한 요소들만 포함하는 컬렉션을 제한 가능
  • IFormattable을 사용하면 객체를 특정 형식으로 변환하는 기능을 쉽게 추가할 수 있다.
  • 기본 타입(int, double, DateTime) 외에도 사용자 정의 클래스에서 직접 구현 가능하다.
  • 제네릭 제약 조건과 함께 사용하면 안전한 코드를 작성할 수 있다.
profile
신입사원...

0개의 댓글