본문 바로가기

Develop/.NET 가이드

[C#] Attributes 특성

반응형

Attributes 특성
Attributes 특성

Attributes 특성

Attributes 특성의 대표적인 특징은 소스 코드에 메타데이터를 추가하여, 런타임 환경에서 소스 코드의 메타데이터에 접근할 수 있다는 점입니다. 특성은 개발자가 자신의 필요에 따라 유연하게 사용하기 보다는 필요한 상황에 .NET 이 제공하는 클래스를 활용하는 방법이 주를 이룹니다. 왜냐하면 특성은 특정 상황에 사용되도록 설계된 기능이기도 하고, 일반적인 응용 프로그램이 소스 코드 의 메타 데이터가 필요한 경우는 드물기 때문입니다.

특성을 활용하는 일반적인 상황

아래와 같은 상황이 개발자가 특성을 활용하게 되는 대부분의 상황에 해당합니다.

  • [DllImport] : 운영체제 네이티브 코드 호출에 필요한 메타데이터를 제공하는 특성
  • [Obsolete] : 개발자 간의 협업을 위해 특정 메소드가 곧 더 이상 사용되지 않음을 나타내는 특성
  • [HttpPost] : Web API를 만들 때 특정 함수가 POST 프로토콜에 대응하는 메서드임을 나타내는 특성

기본적인 특성 사용 예제

특성은 아래 예제 코드처럼 메타데이터를 추가할 선언 위 [ ] 대괄호 안에 작성합니다.


[Serializable]
public class SampleClass
{
    // Objects of this type can be serialized.
}

아래 예제 코드는 외부 네이티브 라이브러리를 호출할 때 사용하는 [DllImport] 특성의 예제입니다.


[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();

아래 예제 코드는 특정 상황에만 코드를 사용할 수 있도록 조건을 지정하는 특성의 예제입니다.


[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
    // ...
}

특성은 아래 예제 코드처럼 특정 대상에게만 적용할 수도 있습니다.


// 메서드에 특성을 적용합니다.
[method: ValidatedContract]
int Method2() { return 0; }

// 반환 타입에 특성을 적용합니다.
[return: ValidatedContract]
int Method3() { return 0; }

특성을 집중적으로 활용하는 특수한 상황

특성을 활용하는 특수한 상황은 주로 Razor 페이지나 XAML 코드와 같이 C# 코드와 함께 동작해야 하는 구문에 집중적으로 사용되고 있습니다. 즉 Visual Studio 나 Visual Code 와 같은 개발환경에서 문자로 작성된 코드를 부분적으로 컴파일하여 구문 오류를 잡아내거나, 코드 변경에 맞추어 화면을 업데이트해야 하는 경우가 특성을 활용하는 특수한 상황입니다.

리플렉션을 사용하여 사용자 지정 특성에 접근하는 예제

// 사용자 지정 특성을 어떻게 사용할지 특성으로 정의합니다.  
[System.AttributeUsage(System.AttributeTargets.Class |  
                       System.AttributeTargets.Struct,  
                       AllowMultiple = true)  // Multiuse attribute.  
]  
// System.Attribute 를 상속하여 사용자 지정 특성을 정의합니다.
public class Author : System.Attribute  
{  
    string name;  
    public double version;  

    public Author(string name)  
    {  
        this.name = name;  

        // Default value.  
        version = 1.0;  
    }  

    public string GetName()  
    {  
        return name;  
    }  
}  

// 클래스에 사용자 지정 특성을 적용합니다. 
[Author("P. Ackerman")]  
public class FirstClass  
{  
    // ...  
}  

public class SecondClass  
{  
    // ...  
}  

// 클래스에 동일한 타입의 특성을 여러 개 적용합니다.
[Author("P. Ackerman"), Author("R. Koch", version = 2.0)]  
public class ThirdClass  
{  
    // ...  
}  

class TestAuthorAttribute  
{  
    static void Test()  
    {  
        PrintAuthorInfo(typeof(FirstClass));  
        PrintAuthorInfo(typeof(SecondClass));  
        PrintAuthorInfo(typeof(ThirdClass));  
    }  

    private static void PrintAuthorInfo(System.Type t)  
    {  
        System.Console.WriteLine("Author information for {0}", t);  

        // 리플렉션을 사용해 특성에 접근합니다.
        System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // Reflection.  

        // 리플렉션으로 접근한 특성 정보를 출력합니다.
        foreach (System.Attribute attr in attrs)  
        {  
            if (attr is Author)  
            {  
                Author a = (Author)attr;  
                System.Console.WriteLine("   {0}, version {1:f}", a.GetName(), a.version);  
            }  
        }  
    }  
}  
/* Output:  
    Author information for FirstClass  
       P. Ackerman, version 1.00  
    Author information for SecondClass  
    Author information for ThirdClass  
       R. Koch, version 2.00  
       P. Ackerman, version 1.00  
*/

특성을 사용하여 C/C++ 공용 구조체 생성

특성을 사용하여 메모리에 구조체가 배치되는 방식을 지정할 수 있습니다.


[StructLayout(LayoutKind.Explicit)]
public class SYSTEM_INFO
{
    [FieldOffset(0)] public ulong OemId;
    [FieldOffset(8)] public ulong PageSize;
    [FieldOffset(16)] public ulong ActiveProcessorMask;
    [FieldOffset(24)] public ulong NumberOfProcessors;
    [FieldOffset(32)] public ulong ProcessorType;
}
반응형