언어/C#

C# 사용자 정의 특성

tsyang 2021. 2. 28. 14:07
  • 이전 글 

tsyang.tistory.com/3

 

Attribute

0. 개요  애트리뷰트(attribute)는 다양한 요소(클래스, 메서드, 필드... 등)에 메타데이터를 추가할 수 있게 해 준다. 1. 필요성 두 가지 팝업 창이 존재한다. 한 가지는 자주 팝업 되고(ex. 이벤트 창)

tsyang.tistory.com

이 글에서는 좀더 자세히 작성

 

사용자 정의 특성의 사용


 

일반

  • 사용자 정의 특성은 단순히 특정 대상에 대해 추가적인 정보를 부가한다. 구체적으로도 컴파일러가 관리 모듈의 메타데이터상에 추가 정보를 기입하는 것에 불과하다.  
  • 또한 사용자 정의 특성은 단순히 특정 타입의 인스턴스이다. 모든 사용자 정의 특성은 직 간접적으로 모두 public 추상 클래스인 System.Attribute 클래스로부터 상속을 받아야 한다. 
  • 사용자 정의 특성을 사용할 때, C# 컴파일러는 Attribute 접미사를 생략하여 이름을 저장할 수 있다.
  • 사용자 정의 특성은 임의의 클래스 인스턴스이므로, 객체 생성을 위해 public 생성자가 반드시 필요하다.

 

 

사용자 정의 특성 매개변수

[DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
  • 위의 코드에서 "Kernel32" 는 생성자의 매개변수로서 전달된 것이다. 이런 생성자의 매개변수를 위치 매개변수(Position Parameter)라 부르며 반드시 시정해줘야 한다. (생정자의 매개변수니까)
  • 나머지 두 매개변수는 DllImportAttribute 객체의 public 인스턴스 필드인 CharSet과 SetLastError에 값을 대입하기 위하여 지정하는 매개변수이다. 이것을 명명된 매개변수(Named Parameter)라 부르고 당연히 생략 가능하다.

 

여러가지 특성을 사용

[Serializable][Flags]
[Serializable, Flags]
[SerializableAttribute()][FlagsAttribute()]

위 코드처럼 다양한 방식으로 여러 특성을 사용할 수 있다. 위의 코드들은 모두 같은 의미를 가진다.

 


사용자 정의 특성 클래스의 정의


정의하기

모든 비추상 특성은 반드시 하나 이상의 public 생성자를 가져야 한다. 

 

사용자 정의 특성을 정의할 때에는 특성을 논리적 상태 컨테이너로서 생각해야 한다. 즉, 생성자와 하나이상의 public 필드나 속성(어떤 경우든 public 필드보다는 속성을 쓰는걸 고려하자)을 정의하여 명명된 매개변수로 부수적 사항을 기재할 수 있도록 하되, 그 외에 public 메서드나 이벤트 혹은 다른 멤버를 제공하면 안 된다.

 

[AttributeUsage(AttributeTargets.Enum, Inherited = false)]

AttributeUsage라는 특성을 사용하여 적용 대상을 정할 수 있다.

 

명명된 매개변수인 Inherited는 적용 대상이 클래스인 경우 해당 클래스를 상속한 클래스에도 동일 특성이 적용되는지를 나타낸다. (즉, Base가 어떤 특성을 사용하면서 Inherted가 true라면 Base의 Derived클래스도 해당 특성이 적용됨)

 

사용자 정의 특성 클래스에서는 기본적인 타입들만 쓸 수 있다. 1차원 배열도 사용할 수 있는데 CLS를 준수하지 않으므로 가급적 사용하지 않는 것이 좋다.

 

 

Conditional 특성

[Conditional("UNITY_EDITOR")]

사용자 정의 특성 클래스에 위와 같이 특성을 적용하면 컴파일러는 UNITY_EDITOR 기호가 정의되어 있는 경우에만 메타데이터에 관련 특성을 부여한다. (단, 사용자 정의 특성 클래스를 정의한 메타데이터는 남는다.)

 


사용자 정의 특성 검출 


IsDefined GetCustomAttribute 메서드로 어떤 사용자 특성이 적용되었는지 검출할 수 있다. 

var attribute = Attribute.GetCustomAttribute(this.GetType(), typeof(FlagsAttribute));
var attribute = this.GetType().GetCustomAttributes(typeof(FlagsAttribute), false);
  • 위처럼 여러 방법으로 접근이 가능하다.
  • 또 단순히 사용자 특성이 적용되었는지 여부를 확인하려면 IsDefined를 쓰는게 더 좋다. (효율적임)
  • 이런 메서드를 사용할때는 문자열 비교를 수행하는데 (메타데이터에서) 이는 시간이 걸리므로 캐싱을 고려하자.
  • 또한 상속한 클래스도 같이 검색하므로 원치 않는다면 sealed클래스로 특성 클래스를 정의하자.

 

Attribute의 GetCustomAttribute(s) 메서드를 사용하면 다음과 같은 일들이 일어난다.

  1. 사용자 정의 특성 클래스의 생성자를 호출한다.
  2. 객체의 속성을 설정하기 위해 Set접근자를 호출한다.
  3. 처음 사용하는 경우 해당 타입의 타입 생성자(정적 생성자)를 호출한다.

따라서 단순히 사용자 정의 특성의 내용을 보기위해서 GetCustomAttribute를 호출했다 하더라도 생정자, Set접근자, 타입 생정자를 거치면서 코드들을 호출하게 되는 것이다. 이는 잠재적인 문제로 남을 수 있다. 

따라서 이런 코드의 호출을 피하고 단순히 특성의 적용 여부를 확인하려면 System.Reflection.CustomAttributeData 클래스를 사용하면 된다. 

 

 

'언어 > C#' 카테고리의 다른 글

C# - 관리 힙과 GC (1)  (2) 2021.03.28
C# Nullable, Null 결합 연산자  (0) 2021.03.06
C# - 델리게이트  (1) 2021.02.21
C# - 배열  (0) 2021.02.10
C# - 문자열 - 1  (0) 2021.02.02