C#의 고급 문자열 템플릿

12753 단어 dotnetcsharp
C# 6에는 문자열 보간 구문이 도입되었습니다. 이 기능을 사용하면 서식이 지정된 텍스트를 코드에서 쉽게 선언할 수 있습니다. 예를 들어:

var name = "World";
var message = $"Hello, {name}"; // "Hello, World"

가장 기본적으로 이것은 C#string.Format 메서드 위에 있는 구문 설탕이지만 훨씬 더 깔끔한 구문을 사용합니다. 그러나 단순히 문자열을 보간하는 것은 종종 위험한 제안입니다. 다음을 고려하세요:

var url = $"https://api.example.com/sample?arg={arg}";

이것은 대부분의 경우 작동하지만 매개변수에 URL에 안전하지 않은 문자가 포함되어 있으면 중단될 수 있습니다. 이는 심각한 보안 취약점을 노출시킬 수도 있습니다. 특히 HTML, 자바스크립트 또는 SQL에 대해 문자열 보간을 수행하는 경우(절대로 수행하지 마십시오!)

포맷 가능한 문자열



C# 언어 사양 깊숙이 숨겨져 있는 것은 문자열 보간에 대한 사소한 참고 사항입니다. 일반적으로 보간된 문자열은 string.Format 에 대한 호출로 컴파일되지만 FormattableString 로 캐스팅할 수도 있습니다. 이 유형은 문자열 템플릿과 여기에 삽입될 객체 배열을 나타냅니다.

var make = "Chrysler";
var model = "Town & Country";
var url = (FormattableString)$"https://api.example.com/vehicles?make={make}&model={model}";

Console.WriteLine(url.Format); // "https://api.example.com/vehicles?make={0}&model={1}";
Console.WriteLine(url.GetArgument(0)); // "Chrysler";
Console.WriteLine(url.GetArgument(1)); // "Town & Country";

이것은 훨씬 더 강력한 문자열 템플릿 도구를 만들 수 있는 몇 가지 흥미로운 기회를 제공합니다. 예를 들어 URL 인수를 자동으로 인코딩하려면 다음을 수행할 수 있습니다.

public static class Format
{
  public static Uri Uri(FormattableString template)
  {
    var encodedArgs = new object[template.ArgumentCount];

    for (var i = 0; i < template.ArgumentCount; i++)
    {
      var original = template.GetArgument(i);
      encodedArgs[i] = HttpUtility.UrlEncode(original);
    }

    return new Uri(string.Format(template.Format, encodedArgs));
  }
}

위의 코드는 새 배열을 만들고 url로 인코딩된 인수로 채웁니다. 그런 다음 원본 템플릿과 새 인코딩된 인수를 사용하여 string.Format를 호출하고 이를 Uri로 반환하여 안전하게 인코딩되었음을 나타냅니다.

그것을 사용하기 위해, 우리는 호출할 수 있습니다

var make = "Chrysler";
var model = "Town & Country";
var url = Format.Uri($"https://api.example.com/vehicles?make={make}&model={model}");

Console.WriteLine(url); // https://api.example.com/vehicles?make=Chrysler&model=Town+%26+Country

사용자 정의 형식



(ab) 사용할 수 있는 또 다른 흥미로운 기능은 사용자 지정 형식 문자열입니다. 기존의 C# 문자열 템플릿에서는 각 인수에 대해 형식을 지정할 수 있습니다.

Console.WriteLine($"Today is {DateTime.Now:yyyy-MM-dd}"); // Today is 2019-12-13

이것은 사실상 호출dateTime.ToString("yyyy-MM-dd")과 동등합니다. IFormattable를 구현하는 모든 개체는 사용자 지정 형식 문자열과 함께 사용할 수 있으므로 문자열 템플릿으로 작업할 때 간단한 구문을 정의할 수 있습니다. 이 예에서는 값을 html로 인코딩하거나 마크다운 형식으로 지정하는 간단한 HTML 템플릿을 설정합니다.

public static HtmlString Html(FormattableString template)
{
  var encodedArgs = new object[template.ArgumentCount];

  for (var i = 0; i < template.ArgumentCount; i++)
  {
    encodedArgs[i] = new HtmlArgument(template.GetArgument(i));
  }

  return new HtmlString(string.Format(template.Format, encodedArgs));
}

class HtmlArgument : IFormattable
{
  public HtmlArgument(object value)
  {
    Value = value;
  }

  public object Value { get; }

  public string ToString(string format, IFormatProvider formatProvider)
  {
    switch (format)
    {
      case "markdown":
        return new Markdown().Transform(Value.ToString());
      case "dangerous-raw-html":
        return Value.ToString();
      default:
        return HttpUtility.HtmlEncode(Value);
    }
  }
}

그러면 이것을 다음과 같이 사용할 수 있습니다.

var html = Format.Html($"<article><h1>{title}</h1>{content:markdown}</article>");
title는 안전하게 HTML로 인코딩되고 content는 마크다운으로 렌더링됩니다.

마무리



C#의 문자열 보간은 편리하지만 일부 함정이 발생할 수 있습니다. 신중하게 사용하지 않으면 극단적인 경우와 깨지거나 취약점이 발생할 수 있습니다. 서식 지정 가능한 문자열은 잘 알려져 있지 않지만 문자열 보간을 보다 스마트하고 컨텍스트 인식하는 데 사용할 수 있는 C#의 잠재적으로 매우 유용한 기능입니다.

좋은 웹페이지 즐겨찾기