어트리뷰트와 리플렉션
Coddy C# 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 70개 중 44번째.
특성은 클래스, 메서드 또는 속성과 같은 코드 요소에 첨부하는 메타데이터 태그입니다. 특성은 코드가 직접 실행되는 방식을 변경하지 않지만, 런타임에 읽을 수 있는 정보를 제공합니다. 리플렉션은 이 메타데이터를 읽는 메커니즘입니다.
대상 요소 위의 대괄호 안에 attribute를 배치하여 적용합니다:
[Obsolete("Use NewMethod instead")]
public void OldMethod() { }
[Serializable]
public class Person
{
public string Name { get; set; }
}Attribute에서 상속하여 custom 특성을 만들 수 있습니다:
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name) => Name = name;
}
[Author("John")]
public class Calculator { }Reflection을 사용하면 System.Reflection 네임스페이스를 통해 런타임에 형식을 검사하고 특성을 읽을 수 있습니다:
Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name); // John메서드와 속성을 탐색하고 동적으로 호출할 수도 있습니다:
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
Console.WriteLine(method.Name);Attribute와 리플렉션은 많은 프레임워크를 강력하게 지원합니다. 직렬화 라이브러리는 이를 사용하여 JSON 출력을 제어하고, 테스트 프레임워크는 이를 사용하여 테스트 methods를 검색하며, 의존성 주입 컨테이너는 이를 사용하여 서비스를 자동으로 연결합니다.
챌린지
쉬움사용자 지정 특성과 리플렉션을 사용하여 플러그인으로 표시된 class를 자동으로 찾고 설명하는 플러그인 검색 시스템을 만들어 보겠습니다. 이는 실제 프레임워크가 런타임에 컴포넌트, 테스트 method 또는 API 엔드포인트를 검색하는 방식과 유사합니다.
코드를 세 개의 파일로 구성합니다.
PluginAttribute.cs:PluginSystemnamespace에PluginAttribute라는 사용자 지정 특성을 Create합니다. 이 특성은 다음과 같아야 합니다.Attribute에서 Inherit해야 합니다.- 읽기 전용 속성 두 개를 Have해야 합니다:
Name(문자열) 및Version(문자열) - constructor를 통해 두 값을 모두 Accept해야 합니다.
Plugins.cs:PluginSystemnamespace에 여러 플러그인 class를 Create합니다. 일부에는PluginAttribute을 적용하고, 하나에는 적용하지 않아야 합니다.ImageProcessor-[Plugin("Image Processor", "1.0")]으로 표시DataExporter-[Plugin("Data Exporter", "2.5")]으로 표시HelperUtility- 어떤 특성도 적용하지 않음(그냥 일반 class입니다)
Program.cs: Main 파일에서 리플렉션을 사용하여PluginAttribute이 있는 모든 class를 검색합니다. 검색된 각 플러그인의 정보를 출력합니다. 다음 작업이 필요합니다.- current assembly에서 모든 형식을 가져옵니다.
- 각 형식에
PluginAttribute이 있는지 check합니다. - 특성의
Name및Version속성을 추출하여 표시합니다.
System.Reflection을 사용하여 형식을 검사하고 사용자 지정 특성을 가져옵니다. GetCustomAttribute<T>() method는 특성이 없으면 null을 반환하므로, 이를 사용하여 실제 플러그인인 class만 filter할 수 있습니다.
검색된 각 플러그인을 다음 형식으로 한 줄에 하나씩 출력합니다.
Plugin: {Name} (v{Version})플러그인은 다음 순서로 출력되어야 합니다. 먼저 ImageProcessor, 그다음 DataExporter입니다. HelperUtility class에는 특성이 없으므로 출력에 나타나지 않아야 합니다.
예상 출력:
Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)이 challenge는 프레임워크가 특성을 marker로 사용하고 리플렉션을 통해 이를 검색하는 방식을 보여 줍니다. 동일한 기법이 dependency injection container, serialization library 및 testing framework를 구현하는 데 사용됩니다!
직접 해보기
using System;
using System.Reflection;
using PluginSystem;
class Program
{
public static void Main(string[] args)
{
// TODO: 현재 어셈블리에서 모든 타입 가져오기
// Hint: Assembly.GetExecutingAssembly().GetTypes() 사용
// TODO: 각 타입을 순회하며 PluginAttribute가 있는지 확인
// Hint: type.GetCustomAttribute<PluginAttribute>() 사용
// TODO: 특성이 존재하면 다음 형식으로 플러그인 정보 출력:
// Plugin: {Name} (v{Version})
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C# 컴파일러