메타데이터 (CLI)

**메타데이터**(Metadata)는 공통 언어 기반 (CLI)에서 코드의 상위 수준 구조를 설명하는 공통 중간 언어 (CIL) 코드 내에 포함된 특정 데이터 구조를 말한다. 메타데이터는 어셈블리에 정의된 모든 클래스 및 클래스 멤버, 그리고 현재 어셈블리가 다른 어셈블리에서 호출할 클래스 및 클래스 메서드 멤버를 설명한다. 메서드의 메타데이터에는 클래스 (및 해당 클래스를 포함하는 어셈블리), 반환형 및 모든 메서드 매개변수를 포함하여 메서드의 완전한 설명이 포함된다.

CLI 언어 컴파일러는 메타데이터를 생성하고 이를 CIL을 포함하는 어셈블리에 저장한다. 런타임이 CIL을 실행할 때 호출된 메서드의 메타데이터가 호출하는 메서드에 저장된 메타데이터와 동일한지 확인한다. 이를 통해 메서드는 정확히 올바른 수의 매개변수와 정확히 올바른 매개변수 유형으로만 호출될 수 있다.

윈도우 8 및 윈도우 폰 8에 있는 윈도우 런타임 애플리케이션 플랫폼은 CLI 메타데이터 형식을 사용하여 지원되는 프로그래밍 언어로 작성된 코드에 대한 컴포넌트 인터페이스를 설명한다. 공통 언어 런타임 내에서의 사용 차이점은 어셈블리가 일반적으로 CIL 명령을 포함하지 않는다는 것이다.

## 특성
개발자는 특성을 통해 코드에 메타데이터를 추가할 수 있다. 특성에는 사용자 지정 특성과 의사 사용자 지정 특성의 두 가지 유형이 있으며, 개발자에게는 동일한 구문을 가진다. 코드의 특성은 컴파일러에게 메타데이터를 생성하라는 메시지이다. CIL에서는 상속 수정자, 범위 수정자 및 opcode 또는 스트림이 아닌 거의 모든 메타데이터도 특성으로 참조된다.

사용자 지정 특성은 `System.Attribute` 클래스를 상속하는 일반 클래스이다. 사용자 지정 특성은 다음 구문을 사용하여 모든 메서드, 속성, 클래스 또는 전체 어셈블리에서 사용할 수 있다: `[AttributeName(optional parameter, optional name=value pairs)]` 예시는 다음과 같다.

```csharp
[Custom]
[Custom(1)]
[Custom(1, Comment="yes")]
```


사용자 지정 특성은 CLI에서 광범위하게 사용된다. Windows Communication Foundation은 특성을 사용하여 서비스 계약을 정의하고, ASP.NET은 이를 사용하여 메서드를 웹 서비스로 노출하며, LINQ to SQL은 이를 사용하여 클래스와 기본 관계형 스키마의 매핑을 정의하고, 비주얼 스튜디오는 이를 사용하여 개체의 프로퍼티를 그룹화하며, 클래스 개발자는 `[Category]` 사용자 지정 특성을 적용하여 개체 클래스의 범주를 나타낸다. 사용자 지정 특성은 애플리케이션 코드에 의해 해석되며 CLR에 의해 해석되지 않는다. 컴파일러가 사용자 지정 특성을 보면 CLR이 인식하지 못하는 사용자 지정 메타데이터를 생성한다. 개발자는 메타데이터를 읽고 이에 따라 작동하는 코드를 제공해야 한다. 예를 들어, 예시에 표시된 특성은 다음 코드로 처리될 수 있다.


```csharp
using System;

class CustomAttribute : Attribute
{
   private int paramNumber = 0;
   private string comment = "";

   public CustomAttribute() { }
   public CustomAttribute(int num) { paramNumber = num; }

   public String Comment
   {
      set { comment = value; }
   }
}
```


클래스 이름은 특성 이름에 매핑된다. Visual C# 컴파일러는 모든 특성 이름 끝에 문자열 "`Attribute`"를 자동으로 추가한다. 따라서 모든 특성 클래스 이름은 이 문자열로 끝나야 하지만 `Attribute`-접미사 없이 특성을 정의하는 것도 허용된다. 항목에 특성을 붙일 때 컴파일러는 리터럴 이름과 `Attribute`가 끝에 추가된 이름(즉, `[Custom]`을 작성하면 컴파일러는 `Custom`과 `CustomAttribute`를 모두 찾는다)을 모두 찾는다. 둘 다 존재하면 컴파일러는 실패한다. 모호성을 피하고 싶다면 특성에 "`@`"를 접두사로 붙일 수 있으므로 `[@Custom]`을 작성하면 `CustomAttribute`와 일치하지 않는다. 특성을 사용하면 클래스의 생성자가 호출된다. 오버로드된 생성자가 지원된다. 이름-값 쌍은 속성에 매핑되며, 이름은 속성 이름을 나타내고 제공된 값은 속성에 의해 설정된다.

때로는 특성을 무엇에 붙이고 있는지에 대한 모호성이 있다. 다음 코드를 고려해 보자.


```csharp
[Orange]
public int ExampleMethod(string input)
{
    //method body goes here
}
```


무엇이 주황색으로 표시되었는가? `ExampleMethod`인가, 그 반환 값인가, 아니면 전체 어셈블리인가? 이 경우 컴파일러는 기본값으로 설정되고 특성을 메서드에 붙인 것으로 간주한다. 의도한 바가 아니거나 작성자가 코드를 명확히 하고 싶다면 특성 대상을 지정할 수 있다. `[return: Orange]`를 작성하면 반환 값을 주황색으로 표시하고, `[assembly: Orange]`를 작성하면 전체 어셈블리를 표시한다. 유효한 대상은 `assembly`, `field`, `event`, `method`, `module`, `param`, `property`, `return`, `type`이다.

의사 사용자 지정 특성은 일반 사용자 지정 특성처럼 사용되지만 사용자 지정 핸들러가 없다. 대신 컴파일러는 특성을 내재적으로 인식하고 그러한 특성으로 표시된 코드를 다르게 처리한다. `Serializable` 및 `Obsolete`와 같은 특성은 의사 사용자 지정 특성으로 구현된다. 의사 사용자 지정 특성은 메타데이터를 설명하기에 적절한 구문이 있으므로 ILAsm에서 사용해서는 안 된다.

## 메타데이터 저장소
어셈블리에는 메타데이터 테이블이 포함된다. 이 테이블은 CIL 사양에 의해 설명된다. 메타데이터 테이블에는 0개 이상의 항목이 있으며 항목의 위치는 해당 인덱스를 결정한다. CIL 코드가 메타데이터를 사용할 때 메타데이터 토큰을 통해 사용한다. 이것은 상위 8비트가 적절한 메타데이터 테이블을 식별하고 나머지 24비트가 테이블에서 메타데이터의 인덱스를 제공하는 32-비트 값이다. 프레임워크 SDK에는 어셈블리의 메타데이터 테이블을 나열하는 라는 샘플이 포함되어 있지만, 이 정보는 개발자에게 거의 유용하지 않다. 어셈블리의 메타데이터는 닷넷 프레임워크 SDK에서 제공하는 ILDASM 도구를 사용하여 볼 수 있다.

CIL 표준에서 메타데이터는 ILAsm (어셈블리 언어) 형식, 저장소를 위한 디스크 표현 형식, 그리고 Portable Executable (PE, .exe 또는 .dll) 형식의 어셈블리에 포함되는 형식으로 정의된다. PE 형식은 디스크 표현 형식을 기반으로 한다.

## 리플렉션

리플렉션은 CLI 메타데이터를 읽는 데 사용되는 API이다. 리플렉션 API는 metainfo와 같은 도구에서 제공하는 리터럴 뷰 대신 메타데이터의 논리적 뷰를 제공한다. 닷넷 프레임워크 버전 1.1의 리플렉션은 클래스와 해당 멤버의 설명을 검사하고 메서드를 호출하는 데 사용될 수 있다. 그러나 메서드의 CIL에 대한 런타임 접근을 허용하지 않는다. 프레임워크 버전 2.0은 메서드의 CIL을 얻을 수 있도록 한다.

## 다른 메타데이터 도구
 네임스페이스 외에도 메타데이터를 처리하는 데 사용할 수 있는 다른 도구도 있다. 마이크로소프트 닷넷 프레임워크는 네이티브 코드로 구현된 CLR 메타데이터 조작 라이브러리를 제공한다. 메타데이터를 검색하고 조작하는 타사 도구로는 PostSharp 및 Mono Cecil도 사용할 수 있다.

## 같이 보기
* 자바 애너테이션

## 각주

분류:공통 언어 기반