사실 C#에서 enum문을 string 형식 으로 사용할 때 사용되는 부분이여서 어떤 문법인지 한번 정리하고 가자.
#정의
메타데이터에서 특성 정의를 빠르고 쉽게 식별할 수 있도록 하는 Attribute에서 직접 또는 간접적으로 파생되는 특성 클래스를 정의하여 자체 사용자 지정 특성을 만들 수 있습니다. 형식을 작성한 프로그래머의 이름을 형식에 태그로 지정한다고 가정합니다. 사용자 지정 Author 특성 클래스를 정의할 수 있습니다.
#사용법(Usage)
-
클래스 정의
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)] public class Author : System.Attribute { private string name; public double version; public Author(string name) { this.name = name; version = 1.0; } }클래스 이름은 특성의 이름인 Author 이며 System.Attribute 상속 받아야 한다. 특정 특성에서만 유효하게 설정하려면 AttributeUsage 을 이용해서 사용.
-
어떻게 사용?
[Author("P. Ackerman", version = 1.1)] class SampleClass { // P. Ackerman's code goes here... // 셋팅한 내용을 추후에 확인해보고 싶거나 이를 이용하여 내용을 구현하는 경우에는 // Type객체를 이용하여 Attribute의 내용을 읽어들일 수 있다. }신기하다..
-
특성 설정
AttributeUsage에는 사용자 지정 특성을 한 번 또는 여러번 사용 할 수 있도록 설정이 가능한데.
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct, AllowMultiple = true) // multiuse attribute ] public class Author : System.Attribute이렇게 AllowMultiple = true 지정 시 아래와 같이 사용 가능하다.
[Author("P. Ackerman", version = 1.1)] [Author("R. Koch", version = 1.2)] class SampleClass { // P. Ackerman's code goes here... // R. Koch's code goes here... } -
코드 요소에 연결된 특성 사용법
특성은 외부 영향이 없으면 어떤 작업도 수행하지 않는다. 특성을 찾아 작업을 수행하려면 일반적으로
리플렉션이필요 하다는데리플렉션관련은 나중에 포스팅하자. 일단, 이러한 특성부여한걸 코드에 사용하고 싶다면 어떻게 해야할까??=> TypeInfo 객체를 이용 GetCustomAttributes 메서드를 활용.
예시로 - 리플렉션을 사용해 클래스에 대한 정보를 가져올 수 있다.
TypeInfo typeInfo = typeof(MyClass).GetTypeInfo(); Console.WriteLine("The assembly qualified name of MyClass is " + typeInfo.AssemblyQualifiedName);다음과 같이 출력.
The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null -
실 사용예시
Atrribute 클래스 정의
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)] public class AuthorTest : System.Attribute { private string name; public double version; public string Name { get => name; set => name = value; } public AuthorTest(string name) { this.Name = name; version = 1.0; } }테스트로 Atrribute부여된 임시 클래스 생성
[AuthorTest("Shin.YoungMyung")] class SampleClass { }Attribute 확인
static void Main(string[] args) { SampleClass _asd = new SampleClass(); Type _type = _asd.GetType(); //현재는 AuthorTest만 부여했으므로 [0]에 AuthorTest만 있다, 만약 다중 부여 시 배열로 넘어온다. System.Object[] _customAttrs = _asd.GetType().GetCustomAttributes(true); }
이런식으로 필요 정보들을 심을 수 있다. 신기하닷
#주의
Attribute 개체가 지연되어 인스턴스화 되는 것에 유의해야 하는데,
즉 GetCustomAttribute 또는 GetCustomAttributes 를 사용해야만 인스턴스화 되고, 매번 인스턴스화 되기도한다.
GetCustomAttributes 를 연속해서 2번 호출하면 2개의 다른 ObsoleteAttribute 인스턴스가 반환된다.
-
BCL(기본 클래스 라이브러리)의 공통 특성
.NET Core 기본 클래스 라이브러리에 기본 제고오디는 몇 가지 유의할 특성
[Obsolete] : 이 특성은 위 예제에서 사용되었으며 System 네임스페이스에 있습니다. 기본 코드를 변경하는 방법에 대해 선언적 설명서를 제공하는 것이 유용합니다. 메시지는 문자열의 형태로 제공될 수 있으며 다른 부울 매개 변수가 컴파일러 경고를 컴파일러 오류로 에스컬레이션하는 데 사용될 수 있습니다.
[Conditional] : 이 특성은 System.Diagnostics 네임스페이스에 있습니다. 이 특성은 메서드(또는 특성 클래스)에 적용할 수 있습니다. 생성자에는 문자열을 전달해야 합니다. 해당 문자열이 #define 지시문과 일치하는 경우 해당 메서드의 호출(메서드 자체는 아님)이 C# 컴파일러에 의해 제거됩니다. 일반적으로 이 특성은 디버깅(진단) 목적으로 사용됩니다.
[CallerMemberName] : 이 특성은 매개 변수에 사용될 수 있으며 System.Runtime.CompilerServices 네임스페이스에 있습니다. 다른 메서드를 호출하는 메서드의 이름을 삽입하는 데 사용되는 특성입니다. 일반적으로 다양한 UI 프레임워크에서 INotifyPropertyChanged를 구현하는 경우 ‘매직 문자열’을 제거하는 방법으로 사용됩니다. - 관련 예제는 아래 링크에 넣어놨다.
#씨샵에서의 활용
enum문을 string 형식 으로 사용 할 수 있는 예제를 작성해보겠다.
-
enum문 필드에 부여할 Attribute 클래스 정의
/// <summary> /// This attribute is used to represent a string value /// for a value in an enum. /// </summary> public class StringValueAttribute : Attribute { #region Properties /// <summary> /// Holds the stringvalue for a value in an enum. /// </summary> public string StringValue { get; protected set; } #endregion #region Constructor /// <summary> /// Constructor used to init a StringValue Attribute /// </summary> /// <param name="value"></param> public StringValueAttribute(string value) { this.StringValue = value; } #endregion } -
속성부여한 필드값을 retrun하는 함수 정의
/// <summary> /// Will get the string value for a given enums value, this will /// only work if you assign the StringValue attribute to /// the items in your enum. /// </summary> /// <param name="value"></param> /// <returns></returns> public static string GetStringValue(this Enum value) { // enum 타입반환 Type type = value.GetType(); // 해당 enum 타입의 value값 필드 정보 넣기 FieldInfo fieldInfo = type.GetField(value.ToString()); // 해당 필드정보의 커스텀속성 찾기. StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes( typeof(StringValueAttribute), false) as StringValueAttribute[]; // Return the first if there was a match. return attribs.Length > 0 ? attribs[0].StringValue : null; } -
실 코드 사용
// enum 정의 public enum TestEnum : int { [StringValue("a")] //이부분이 string으로 쓸 부분 정의 develop = 1, [StringValue("b")] staging = 2 } static void Main(string[] args) { TestEnum tetEnumValue = TestEnum.develop; string whatString = help.Funcs.GetStringValue(tetEnumValue); // "a"가 반환 됨을 알 수 있다. }