개발언어/C#

[C#] 어트리뷰트(Attribute)

내꺼블로그 2024. 5. 9. 15:40

어트리뷰트(Attribute)

어트리뷰트(attribute)란 프로그램 및 프로그래밍 요소(클래스, 속성, 메서드, 이벤트 등)에 메타데이터를 추가하는 기능을 의미한다. 메타데이터란 프로그램에 정의된 형식에 대한 정보를 의미한다.

 

어트리뷰트를 사용할 때에는 기본적으로 사용하고자 하는 요소 위에 [어트리뷰트이름(매개변수)] 형태로 사용하면 된다. 어트리뷰트는 .NET에서 기본적으로 제공하는 어트리뷰트와 사용자 정의로 사용할 수 있는 어트리뷰트가 있다.

 


 

공통 어트리뷰트

.NET에서 기본적으로 제공하는 어트리뷰트는 다음과 같다.(이외에도 더 있음)

ObsoleteAttribute 이제는 쓸 수 없는 요소임을 경고 메시지를 통해 나타냄
SerializableAttribute 클래스를 직렬화 할 수 있음을 나타냄
DllImportAttribute 메서드가 관리되지 않은 DLL에서 볼 수 있는 정적 진입점임을 나타냄
ConditionalAttribute 전처리기에 정의되어 있지 않으면 해당 요소가 무시되어야 함을 컴파일러에 알림
AttributeUsageAttribute 다른 어트리뷰트에서 적용 가능한 요소 값을 지정

주로 SerializableAttribute와 DllImportAttribute를 사용한다.

 

 

ObsoleteAttribute

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestAttribute
{
    public class Method
    {
        [Obsolete("더 이상 사용하지 않는 메서드입니다.")]
        public void OldMethod()
        {
            Console.WriteLine("old method");
        }

        public void NewMethod()
        {
            Console.WriteLine("new method");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Method m = new Method();
            m.OldMethod();
            m.NewMethod();
        }
    }
}

코드에서 보이는 것과 같이 OldMethod에 obsolete 어트리뷰트를 추가해주었다.

obsolete 어트리뷰트는 사용하지 않을 요소 위에 [obsolete()]를 추가해주면 된다. obsolete 어트리뷰트 매개변수 값으로는 string 형태의 경고 메시지를 할당할 수 있다.

obsolete 어트리뷰트는 System 네임스페이스에 정의되어 있다.

 

결과

 

실행하였을 때 결과가 나오긴 하지만 다음과 같은 오류가 뜨며, 실제 코드에도 OldMethod를 호출하는 부분에서 밑줄이 쳐진 것을 확인할 수 있다.

 

 

Obsolete 어트리뷰트의 매개변수 2번째 인자로 bool 값을 할당할 수 있다.(기본값은 false)

이때 true를 입력하면 보이는 사진과 같이 경고가 아닌 오류를 띄우게 된다.

 

 

ConditionalAttribute

 

#define TEST

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestAttribute
{
    public class Method
    {
        [Conditional("TEST")]
        public void PrintMethod()
        {
            Console.WriteLine("test...");
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Method m = new Method();
            m.PrintMethod();
        }
    }
}

Conditional 어트리뷰트는 해당 이름이 전처리기에 정의되어 있지 않으면 해당 요소를 무시하도록 컴파일러에 알린다.

처리할 요소 위에 [Conditional()]를 추가해주면 된다. 매개변수로는 string 형식의 정의될 이름이다.

Conditional 어트리뷰트를 사용하기 위해서는 System.Diagnostics 네임스페이스를 선언해야 한다.

 

전처리기에 TEST가 정의되어 있으므로 메서드가 실행된 것을 볼 수 있다.

 

전처리기에 주석을 처리해보면 메서드가 실행되지 않은 것을 볼 수 있다.

 

 

DllImportAttribute

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace TestAttribute
{

    internal class Program
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

        static void Main(string[] args)
        {
            MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
        }
    }
}

DllImport 어트리뷰트를 사용하여 user32.dll에서 사용하는 MessageBox 메서드를 호출한 코드이다.

사용할 때 임포트할 메서드 위에 [DllImport()]를 추가해주면 된다. 매개변수로는 사용할 dll의 이름을 적으면 된다. 

 

 

다음과 같이 뜬다


 

사용자 정의 어트리뷰트

사용자 정의로 어트리뷰트를 사용하기 위해서는 먼저 System.Attribute 클래스를 상속받아 정의해야 한다.

 

using System;
using System.Reflection;

namespace TestAttribute
{
    [AttributeUsage(AttributeTargets.Method)]
    public class CustomizeAttribute : Attribute
    {
        public bool isActive {  get; set; }

        public CustomizeAttribute(bool isActive)
        {
            this.isActive = isActive;
        }
    }
    internal class Program
    {
        
        public class CustomClass
        {
            [Customize(true)]
            public void Run()
            {
                Console.WriteLine("is running");
            }

            [Customize(false)]
            public void Fail()
            {
                Console.WriteLine("is failed");
            }
        }


        static void Main(string[] args)
        {
            CustomClass class1 = new CustomClass();

            var methods = class1.GetType().GetMethods();
            foreach (var method in methods)
            {
                var att = method.GetCustomAttribute(typeof(CustomizeAttribute)) as CustomizeAttribute;
                if (att != null)
                {
                    if(att.isActive)
                        method.Invoke(class1, null);
                }
            }
        }
    }
}

대충 구현해 본 코드

사실 아직까지도 이걸 왜 쓰는건가 아리까리한지라 일단 '구현해 본다'라는 느낌으로만 해봤다.

 

AttributeUsage

사용자 정의 어트리뷰트를 구현할 때 어떤 요소에 추가할 것인지, 여러 개 추가해도 괜찮을 건지 등의 조건을 걸어두는 어트리뷰트이다.

AttributeTargets는 적용할 요소의 대상을 선택하라는 의미. Class면 Class에 사용하고, Struct면 Struct에 사용해야 하는데, 논리 연산자를 사용해서 원하는 대상들을 정할 수 있다.

AllowMultiple은 적용할 요소에 어트리뷰트를 여러 개 설정하게끔 할건지 아닐건지를 정할 수 있으며, true일 경우 하나의 대상에 지정해놓은 어트리뷰트 여러 개를 추가할 수 있다. false가 default

 

 

내가 구현해놓은 코드는 어트리뷰트의 필드로 isActive를 지정하여 isActive가 true인 메서드만 호출되게끔 구현하였다.

그리고 메서드의 어트리뷰트 정보를 알아내기 위해 리플렉션(reflection)이 사용되었다.

 

isActive가 true인 Run메서드만 호출된 모습이다. isActive가 false인 Fail메서드는 호출되지 않았다.

 

 

 

 

.

.

.

 

사실 잘 쓰려면 더 잘 쓸 수 있지 않을까 싶은데 아직까지는 이걸 어디에 쓰는 건지 감이 잘 오지 않는다... 공부하다보면 알게되려납..?