ISO 4217 통화 레퍼런스 for .NET — 강력한 타입 지정 및 프로덕션 레디

발행: (2025년 12월 12일 오후 07:41 GMT+9)
3 min read
원문: Dev.to

Source: Dev.to

Overview

.NET에서 통화를 다루는 일은 겉보기에 간단해 보이지만, 실제로는 엉망이 될 수 있습니다. 문자열 기반 코드, 일관성 없는 대소문자, 폐지된 통화, 특수 단위, 그리고 다양한 예외 상황이 로직을 조용히 깨뜨릴 수 있습니다. 흔히 발생하는 함정은 다음과 같습니다:

if (currencyCode == "usd" || currencyCode == "Usd" || currencyCode == "USD")
{
    // ...
}

또는 “개선된” 버전:

if (string.Equals(currencyCode, "usd", StringComparison.OrdinalIgnoreCase))
{
    // ...
}

그리고 더 나쁜 경우:

if (currency == "XXX") { /* ??? */ }
if (currency == "BYR") { /* replaced by BYN */ }

이 모든 문제는 통화를 단순 문자열로 취급하기 때문에 발생합니다. ISO 4217은 표준이므로, 이를 강력히 타입화된 방식으로 사용할 수 있어야 합니다.

The Idea

컴파일 타임에 Source Generator를 사용해 ISO 통화 타입을 생성합니다. 그 결과가 HawkN.Currency.Reference.Iso4217 라이브러리입니다.

  • NuGet:
  • GitHub:

.NET용 경량, 무의존성, 소스 생성 기반, 프로덕션 준비된 ISO 4217 레퍼런스 라이브러리입니다.

Installation

CLI

dotnet add package HawkN.Currency.Reference.Iso4217 --version 8.0.1

Package Manager

Install-Package HawkN.Currency.Reference.Iso4217 -Version 8.0.1

Registration

services.AddCurrencyService();

Basic Usage

Console Application

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddCurrencyService();
    })
    .Build();

var currencyService = host.Services.GetRequiredService<ICurrencyService>();

Minimal API Injection

app.MapGet("/currencies", ([FromServices] ICurrencyService svc) => svc.Query().Build());

Querying Currencies

Include Specific Types

var currencies = currencyService.Query()
    .Includes
        .Type(CurrencyType.Fiat)
        .Type(CurrencyType.SpecialUnit)
        .Type(CurrencyType.SpecialReserve)
        .Type(CurrencyType.PreciousMetal)
    .Build();

Currency Types

  • Fiat – 예: USD, EUR, JPY
  • SpecialUnit – 예: SDR, IMF 단위
  • SpecialReserve
  • PreciousMetal – 예: XAU, XAG, XPT, XPD

Filter Only Fiat Currencies

var fiat = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Build();

Exclude Specific Codes

var filtered = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Without(w => w.Codes(nameof(CurrencyCode.EUR), nameof(CurrencyCode.USD)))
    .Build();

Conditional Selection

var selected = currencyService.Query()
    .Includes.Type(CurrencyType.Fiat)
    .Where(x => x.Code is "EUR" or "USD")
    .Build();

Validation

var ok = currencyService.TryValidate("AFN", out var result);

또는 강력히 타입화된 enum을 사용:

var ok = currencyService.TryValidate(CurrencyCode.AFN, out var result);

Retrieval

By String

var afn = currencyService.Get("AFN");

By Enum

var afn = currencyService.Get(CurrencyCode.AFN);

Historical Currencies

var historical = currencyService.GetAllHistorical();
foreach (var c in historical)
{
    Console.WriteLine($"{c.Code} - {c.Name} (Withdrawn: {c.WithdrawnOn})");
}

Benefits

  • 문자열 리터럴 대신 컴파일 타임 안전성 제공.
  • 수동 유지보수가 필요 없는 ISO‑준수 데이터.
  • 매우 빠른 조회 속도.
  • 어디서든 IntelliSense가 제공되는 뛰어난 개발자 경험.
  • AOT‑지원 및 리플렉션 불필요.
  • 정적이며 결정적인 데이터.
  • CI 워크플로우를 통한 자동 업데이트.

Project Background

이 프로젝트는 작은 실험으로 시작되었습니다: “Source Generator로 모든 ISO 4217 통화를 생성할 수 있을까?”

  • GitHub:
  • NuGet:

즐거운 코딩 되세요!

Back to Blog

관련 글

더 보기 »

.NET에서 NuGet 패키지 사용 마스터하기

NuGet은 실제로 무엇인가요? NuGet을 .NET의 Amazon이나 Mercado Libre라고 생각해 보세요. 가구의 모든 나사를 직접 만들지 않고, 가게에 주문하듯이요. - 패키지…

LINQ 식에서 다중 열거

다중 열거는 LINQ 쿼리가 IEnumerable 컬렉션을 생성하고 이를 여러 번 반복할 때 발생합니다. 이는 특히 성능 문제를 일으킬 수 있습니다.