콘텐츠로 이동

C# 12 Interceptors — 컴파일 타임 메서드 교체

Interceptors는 C# 12에서 도입된 실험적 기능으로, 특정 호출 사이트(call site)의 메서드 호출을 컴파일 타임에 다른 메서드로 교체합니다. Source Generator와 함께 사용해 AOT 최적화, 성능 개선, 코드 분석 도구 등에 활용됩니다.

주의: .NET 8 기준 실험적 기능([Experimental])입니다. 향후 API가 변경될 수 있습니다.


.csproj
<PropertyGroup>
<InterceptorsPreviewNamespaces>MyApp.Generated</InterceptorsPreviewNamespaces>
</PropertyGroup>

// 원본 코드
namespace MyApp;
public class Greeter
{
public string Hello(string name) => $"Hello, {name}!";
}
// 호출 사이트 (Program.cs, 5번째 줄 14번째 열)
var g = new Greeter();
var msg = g.Hello("World"); // ← 이 호출을 교체
// Generated/Interceptors.cs (Source Generator 출력)
using System.Runtime.CompilerServices;
namespace MyApp.Generated;
file static class GreeterInterceptors
{
[InterceptsLocation("Program.cs", line: 5, character: 14)]
public static string Hello_Intercepted(this Greeter g, string name)
=> $"안녕하세요, {name}!"; // 교체된 구현
}

[Generator]
public class InterceptorGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var calls = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (node, _) => node is InvocationExpressionSyntax,
transform: (ctx, _) => GetCallInfo(ctx))
.Where(info => info is not null);
context.RegisterSourceOutput(calls, (ctx, info) =>
{
var source = GenerateInterceptor(info!);
ctx.AddSource($"Interceptor_{info!.Location}.g.cs", source);
});
}
}

ASP.NET Core의 Minimal API는 Interceptors를 이용해 JsonSerializer.Deserialize<T>() 호출을 AOT 친화적인 Source Generated 버전으로 자동 교체합니다.

// 원본 호출
app.MapPost("/user", (User u) => Results.Ok(u));
// 컴파일 후 — Interceptor가 AOT 직렬화 코드로 교체
// JsonSerializer.Deserialize<User>(...)
// → UserJsonContext.Default.User 사용
// 원본
logger.LogInformation("User {Id} logged in", userId);
// Interceptor → 컴파일 타임 LoggerMessage 생성으로 교체
// → 런타임 문자열 보간 제거

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class InterceptsLocationAttribute : Attribute
{
public InterceptsLocationAttribute(string filePath, int line, int character) { }
}
  • filePath: 소스 파일 경로 (프로젝트 기준 상대 경로)
  • line: 호출 사이트의 줄 번호 (1 기반)
  • character: 호출 사이트의 열 번호 (1 기반)

항목내용
상태실험적 기능 (Experimental)
적용 범위인스턴스 메서드, 정적 메서드, 확장 메서드
불가 대상생성자, 연산자, 속성 접근자
도구Source Generator 없이 수동 작성도 가능 (비권장)

Interceptors는 직접 사용보다는 프레임워크와 라이브러리가 내부적으로 활용하는 메커니즘입니다. ASP.NET Core, EF Core 등이 AOT 최적화를 위해 적극 채택 중이며, 동작 원리를 이해하면 생성된 코드를 읽고 디버깅하는 데 큰 도움이 됩니다.