[C#] 특성(Attribute)

Running boy·2023년 8월 6일
0

컴퓨터 공학

목록 보기
19/36

특성(Attribute)

특성은 메타데이터에 원하는 기록을 남기거나, 타입의 기능을 확장할 때 사용된다.

일반적으로 개발자는 주석을 사용해 기록을 남기지만 주석은 컴파일 과정에서 제외되기 때문에 메타데이터에 포함되지 않는다.

하지만 의도적으로 메타데이터에 기록을 포함하고 싶은 경우(ex. 저작권) 특성을 활용할 수 있다.


System.Attribute

특성은 클래스와 같다.

클래스로 정의하며 'System.Attribute'를 상속받는다.

class TestAttribute : System.Attribute // ※관례적으로 특성을 정의할 때 식별자를 "~Attribute"로 정한다
{

}

[TestAttribute]
class TestClass1
{

}

[Test] // 사용할 때 Attribute 접미사는 생략해도 된다.
class TestClass2
{

}

[Test()] // 클래스이기 때문에 생성자로 표현할 수 있다.
class TestClass3
{

}

class TestClass4
{
    TestAttribute test = new TestAttribute(); // 클래스이기 때문에 new 키워드를 사용하여 인스턴스를 생성하는 것 또한 가능하다.
}

확장1

특성의 생성자에 매개변수를 추가하여 확장할 수 있다.

class TestAttribute : System.Attribute
{
    string name;

    public TestAttribute(string name)
    {
        this.name = name;
    }
}

[Test("Jerod")]
class TestClass
{
    
}

확장2

생성자의 매개변수가 아니라 프로퍼티를 사용하여 확장할 수도 있다.

class TestAttribute : System.Attribute
{
    string name;
    public int Age { get; set; }

    public TestAttribute(string name)
    {
        this.name = name;
    }
}

[Test("Jerod", Age = 27)]
class TestClass
{

}

생성자의 뒤에 나열하며 반드시 필드명을 명시해야 된다.


System.AttributeUsageAttribute

특성을 정의할 때 특성이 적용될 대상을 지정할 수 있다.

이 용도로 닷넷은 'System.AttributeUsageAttribute'를 제공한다.

namespace System
{
    /* By default, attributes are inherited and multiple attributes are not allowed */
    [AttributeUsage(AttributeTargets.Class, Inherited = true)]
    public sealed class AttributeUsageAttribute : Attribute
    {
        private readonly AttributeTargets _attributeTarget;
        private bool _allowMultiple;
        private bool _inherited;

        internal static readonly AttributeUsageAttribute Default = new AttributeUsageAttribute(AttributeTargets.All);

        public AttributeUsageAttribute(AttributeTargets validOn)
        {
            _attributeTarget = validOn;
            _inherited = true;
        }

        internal AttributeUsageAttribute(AttributeTargets validOn, bool allowMultiple, bool inherited)
        {
            _attributeTarget = validOn;
            _allowMultiple = allowMultiple;
            _inherited = inherited;
        }

        public AttributeTargets ValidOn => _attributeTarget;

        public bool AllowMultiple
        {
            get => _allowMultiple;
            set => _allowMultiple = value;
        }

        public bool Inherited
        {
            get => _inherited;
            set => _inherited = value;
        }
    }
}

AttributeTargets: enum 타입이며, 특성이 적용되는 대상을 지정한다. '|' 비트 연산으로 복수대상을 지정할 수 있다.

AllowMultiple: 동일한 특성을 중복으로 부여할 수 있다. 디폴트값은 false이다.

Inherited: 특성을 지정한 대상을 상속받는 타입도 자동으로 특성을 물려받는다. 디폴트값은 true이다.

예제

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field)]
class TestAttribute : System.Attribute
{
    
}

[Test] // OK
class TestClass1
{
    [Test]
    [Test] // 동일한 특성이 중복으로 사용되어 컴파일 에러 발생
    int testField;

    [Test] // 지정되지 않는 대상에 사용되어 컴파일 에러 발생
    public void TestMethod()
    {

    }
}

[type : Test] // AttributeTarget이 여러개일 경우 구분을 위해 이러한 구문도 지원한다.
class TestClass2
{

}

AssemblyInfo.cs

비주얼 스튜디오에서 프로젝트를 빌드하면 AssemblyInfo.cs 파일이 생성된다.

해당 파일은 어셈블리 수준에서 적용되는 특성만을 모아두는 용도이다.

// 생략
[assembly: System.Reflection.AssemblyCompanyAttribute("TestProject")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("TestProject")]
[assembly: System.Reflection.AssemblyTitleAttribute("TestProject")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// 생략

그림1


알아두면 좋은 Attribute

Conditional Attribute

Attribute를 상속받은 클래스나 메서드에 사용할 수 있으며 해당 클래스나 메서드에 전처리를 해준다.

인자로 넘긴 string과 동일한 전처리 상수가 정의되지 않은 경우, 컴파일러는 해당 클래스나 메서드를 무시한다.

public class Program
{
    [Conditional("DEBUG")] // DEBUG 전처리 상수는 디버그 빌드에서 자동으로 관리된다.
    class TestAttribute : Attribute
    {

    }

    public static void Main()
    {
        TestMethod();
    }

    [Conditional("DEBUG"), Conditional("TEST")] // DEBUG or TEST
    [Test]
    static void TestMethod()
    {
        Console.WriteLine("Test");
    }
}

// 출력:
// Test

위 예시를 통해 알 수 있는 Conditional의 특징은
1. 중복 부여가 가능하다. (중복 부여시 하나의 전처리 상수만 만족해도 된다.)
2. Conditional을 부여한 메서드는 반드시 void 반환형이어야 한다. (컴파일 에러 발생. 그 이유는 조금만 생각해도 알 수 있다.)


Flags Attribute

이전 포스트에서 정리했다.



참고 자료
시작하세요! C# 10 프로그래밍 - 정성태
Microsoft 공식 문서 - AttributeTargets 열거형

profile
Runner's high를 목표로

0개의 댓글