기본 패턴
csharp
// 내장 어트리뷰트
[Obsolete("V2 API를 사용하세요", error: false)]
public void OldMethod() { }
// 커스텀 어트리뷰트 선언
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class AuditAttribute : Attribute
{
public string Reason { get; }
public AuditAttribute(string reason) => Reason = reason;
}
// 적용
[Audit("결제 처리 — 감사 로그 필수")]
public void ProcessPayment() { }
// 리플렉션으로 읽기
var attr = typeof(MyClass)
.GetMethod("ProcessPayment")
?.GetCustomAttribute<AuditAttribute>();
Console.WriteLine(attr?.Reason);설명
어트리뷰트란
어트리뷰트는 클래스, 메서드, 프로퍼티 등에 메타데이터를 부착하는 방법입니다. 컴파일러, 런타임, 외부 도구(직렬화, ORM, DI 등) 가 이 메타데이터를 읽어 동작을 결정합니다. 코드 자체는 바꾸지 않고 의미를 추가할 수 있습니다.
주요 내장 어트리뷰트
[Obsolete] 는 사용 중단을 알리는 가장 흔한 어트리뷰트입니다. error: true로 설정하면 컴파일 오류로 격상됩니다.
csharp
[Obsolete("GetUser() 대신 GetUserAsync()를 사용하세요")]
public User GetUser(int id) { ... }
[Obsolete("제거 예정 — 즉시 마이그레이션 필요", error: true)]
public void LegacyLogin() { }[CallerMemberName] 은 호출자 이름을 컴파일 시점에 자동 주입합니다. 로깅과 INotifyPropertyChanged 구현에 유용합니다.
csharp
void Log(string message,
[CallerMemberName] string caller = "",
[CallerLineNumber] int line = 0)
{
Console.WriteLine($"[{caller}:{line}] {message}");
}
// 호출
Log("시작"); // [ProcessPayment:42] 시작커스텀 어트리뷰트 선언
Attribute를 상속하고 [AttributeUsage] 로 적용 가능한 대상과 규칙을 제한합니다.
csharp
[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, // 같은 대상에 중복 적용 여부
Inherited = true // 파생 클래스에도 상속 여부
)]
public class RequiresRoleAttribute : Attribute
{
public string Role { get; }
public RequiresRoleAttribute(string role) => Role = role;
}
[RequiresRole("Admin")]
public void DeleteUser(int id) { }리플렉션으로 읽기
런타임에 GetCustomAttribute<T>() 로 어트리뷰트를 읽을 수 있습니다.
csharp
var method = typeof(UserService).GetMethod("DeleteUser");
var attr = method?.GetCustomAttribute<RequiresRoleAttribute>();
if (attr != null)
Console.WriteLine($"필요 권한: {attr.Role}"); // "Admin"
// 여러 개 읽기
var attrs = method?.GetCustomAttributes<RequiresRoleAttribute>();
// 존재 여부만 확인
bool has = method?.IsDefined(typeof(RequiresRoleAttribute)) ?? false;빠른 정리
| 어트리뷰트 | 용도 |
|---|---|
[Obsolete] | 사용 중단 경고/오류 |
[Flags] | enum 비트 플래그 조합 허용 |
[Serializable] | 직렬화 허용 표시 |
[CallerMemberName] | 호출자 이름 컴파일 시 주입 |
[CallerLineNumber] | 호출 줄 번호 주입 |
[JsonPropertyName] | JSON 직렬화 키 이름 지정 |
[Required] | 모델 유효성 검사 |
[AttributeUsage] | 커스텀 어트리뷰트 적용 규칙 정의 |
주의할 점
어트리뷰트는 런타임에 리플렉션으로 읽으므로 반복 호출 시 성능 비용이 있습니다. 요청마다 GetCustomAttribute()를 호출하는 대신 결과를 ConcurrentDictionary 등에 캐싱해 재사용하세요.
어트리뷰트 생성자에는 컴파일 시점에 알 수 있는 상수값(string, int, Type, enum 등)만 사용할 수 있습니다. 런타임에 결정되는 값은 전달할 수 없습니다.
참고 링크
2 sources