반응형
어트리뷰트(Attribute)

 

Attribute(어트리뷰트, 속성)는 어셈블리, 모듈, 클래스, 구조체, 열거형변수, 생성자, 메소드, 프로퍼티, 필드, 이벤트, 인터페이스, 파라미터, 반환값, 델리게이트 같은 프로그래밍 요소에 대해 메타정보를 포함 시킬수 있는 기술이다. 프로그래밍요소에 추가정보를 기술을 통해서 런타임용코드를 설명하거나 런타임에서 응용프로그램 동작에 영향을 주거나  CLR에게 추가정보를 제공한다. 어트리뷰트 정보는 어셈블리의 메타데이터 내에 저장되며 리플렉션을 통해서 실행시간에 추출가능하다. 또 표준어트리뷰트(내장어트리뷰트)와 사용자정의 어트리뷰트로 나뉜다. 교과서 적인 이야기를 막 했는데 코드를 읽는데 어트리뷰트를 모르면 눈에 걸리적 거리고 신경 쓰여서 가독성과 이해력이 떨어지므로 알아야 한다. 사용자 정의 클래스 등을 만들 때 설명을 포함시키거나 디버그 정보 활용, API함수 사용 정도로 흔히 사용한다.

 

 

 

1. 어트리뷰트 구문

 

[attribute(positional_parameters, name_parameter = value, ...)] element

[attribute명(위치매개변수 , 명명된 매개변수=값,...)]  프로그래밍요소

 

어트리뷰트 역시 클래스의 일종으로 '[]' 를 제외하고는 일반적인 함수와 사용법이 유사하다. 파라미터는 필수항목이고 인수의 순서를 지켜야 하는 위치지정 파라미터(positional_parameter)와 사용자의 필요에 따라서 선택적으로 사용되고 매개변수 이름과 함께 사용하는 명명 파라미터(name_parameter)가 있다. 파라미터 이름과 값을 같이 사용할 경우 위치에 상관없이 사용할 수 있다. 
 

 

 

 

2. 어트리뷰트의 종류

 .NET 에서 제공되는 내장 어트리뷰트(Predefined Attributes)는 General attributes, COM interoperability attributes, Transaction handling attributes, Visual designer component building attributes 로 나뉜다.

 

2.1 General attributes

일반어트리뷰트(General attributes)는  Conditional Attribute와 DllImport Attribute가 있다.

 

2.1.1 Conditional Attribute

Conditional Attribute는 디버깅을 위해 사용된다. 다음 예 처럼 사용자가 정의한 symbol이 있으면 해당 메서드를 실행 한다. Conditional Attribute는 클래스나 구조체 안에 있는 메소드 에서만 사용 할 수 있고 리턴 타입이 void 타입 이어야 한다.

 

#define DEBUGGING    

// #undef DEBUGGING     //어튜리뷰트 사용 해제
using System;  
using System.Diagnostics;
namespace CSharpStudy  
{  
       class  MainClass  
       {  
           [Conditional("DEBUGGING")]  
           public static void DebugPrint()  
           {  
              Console.WriteLine("DEBUGGING");  
           }  

           [STAThread]  
           static void Main(string[] args)  
           {  
              DebugPrint();  
           }
       }
}

다음의 코드 처럼 메서드에 대해 여러 Conditional Attribute를 붙이게 되면 그 중 하나만 위치지정 파라미터가 정의 되어 있어도 그 메소드를 실행 시킨다. 

 

#define SOUNDCARD
#define SPEAKER

using System;
using System.Diagnostics;

namespace CSharpStudy
{

    class Test
    {

        static void Main()
        {
            isSound();

            Console.ReadLine();
        }

        [Conditional("SOUNDCARD"), Conditional("SPEAKER")]
        static void isSound()
        {
            isSpeaker();
        }

        static void isSpeaker()
        {
            Console.WriteLine("음악을 들을 수 있습니다...");
        }


    }

}

 

 

2.1.2 DllImport 어트리뷰트
DllImport Attribute는 C#안에서 Unmanaged Code를 사용 할 수 있게 한다. Unmanaged Code란 .Net 환경 밖에서 개발된 Win32 API 같은 코드를 가리킨다. DllImport Attribute는 System.Runtime.InteropServices 네임스페이스 안에 정의 되어 있다. 사용방법은 위치지정 파라미터로 사용 할 DLL 파일을 인자로 넘겨 주면 된다.

[DllImport("MyDLL.dll", EntryPoint="MessageBox")]
public static extern int MyFunction(string param1);

 


using System;
using System.Runtime.InteropServices;

class Test
{
        //User32.dll 파일안의 MessageBox 함수를 불러와서 사용하는 예이다. DllImport Attribute를
        //이용하여 사용할 코드가 포함되어 있는 DLL을 넘겨주고 extern 키워드를 통해 사용하려고 하는
        //메소드가 외부에 있음을 알린다. 이렇게 하면 닷넷 환경 밖에서개발된 코드들도 C#안에서 쓸수 있다.
        [DllImport("User32.Dll")]
        public static extern int MessageBox(int h, string m, string c, int type);

 

        static void Main()
        {
                MessageBox(0, "Hello World!", "타이틀", 0);  

        }
}

 

 

 

2.2 Visual Designer Component-Building 어트리뷰트
사용자정의 컨트롤을 비주얼디자이너에서 속성(Property)이나 클래스를 어떻게 표시할지를 정한다.
Browseable 

프로퍼티나 이벤트가 비주얼 디자이너의 속성창에 나타나야하는지 명시
DefaultEvent

컨트롤의 기본 이벤트를 지정
DefaultProperty

컨트롤의 기본 속성으로 지정
DefaultValue

컨트롤의 기본값 지정
Persistable

속성이 저장되어야 하는지 프로퍼티 저장되어야 하는지, 저장되어야 한다면 어떻게 저장 되어야하는지 명시
Category

속성창에서 프로퍼티나 이벤트가 어느 카테고리에 들어가야 하는지 명시
Description

프로퍼티나 이벤트가 선택 되었을 때 프로퍼티 창 밑에 나오는지 설명을 정의
Localizable

프로퍼티가 폼이 지역화되었을 때 리소스 파일에 저장되어야함을 명시
Persistable

프로퍼티가 저장되어야 하는지, 저장되어야 한다면 어떻게 저장되어야 하는지 명시  

 

 

 

2.3 COM Interoperability 어트리뷰트
ComRegisterFunction

.Net 어셈블리를 COM이 사용할 수 있도록 레지스트에 등록할 때 호출되는 함수임을 나타낸다.
ComImport

클래스나 인터페이스의 정의가 COM 타입 라이브러리로부터 가져온 것을 나타낸다.
ComUnregisterFunction

.Net  어셈블리를 레지스트리로부터 삭제할 때 호출 되는 함수임을 나타낸다.
InterfaceType

관리된 인터페이스가 COM에 노출 되었을 때 그 인터페이스가 IDispatch인지 IUnknown인지 또는 dual인터페이스인지 나타낸다.
Displd

함수(메소드)나 속성에 사용될 Dispatch ID를 나타낸다.
In

필드나 파라미터가 input값으로 사용됨을 나타냄
Out

해당 인자 값을 통해서 불려진 함수가 결과 값을 리턴할  때 마샬링을 해줘야 함을 나타낸다.
Progld

클래스를 사용하기 위한 Prog ID를 나타낸다.
MarshalAs

데이터가 COM과 관리(managed)되는 사이에서 어떻게 마샬링되는지 정보를 나타낸다.
HasDefaultInterface

클래스가 디폴트 COM 인터페이스를 가지고 있음을 명시적으로 나타낸다.

 

 


2.4 Transaction handling attributes
COM+ 환경에서 트랜젝션 관리를 위해 사용된다.

[Transaction(TransactionOption.Required)]
public class MyTransactionalComponent
{
    ...
}

 

 

 

 

 

3 어트리뷰트 사용 패턴

 

3.1 Multiple Attribute의 사용
한 개의 프로그래밍 요소에 한 개 이상의 어트리뷰트를 사용할 수 있으며 어트리뷰트정의에서 허용한다면 같은 어트리뷰트를 여러번 사용할 수도 있다.

 

[Transaction(TransactionOption.Required)]
[DefaultProperty("Balance")]
public class FinancialComponent: System.WinForms.UserControl
{

   public long Balance
    {
        ...
    }

    ...
}

 

// 어트리뷰트는 기본적으로 한 어트리뷰트에 한 개의 인스턴스만 사용 가능하지만

// AllowMultiple을 true로 지정하면 위에서와 같이 같은 어트리뷰트를 여러 개 사용 가능하다.

[CustomAttribute.DeveloperInfo("한개발", Date="12-12-2000"),
 CustomAttribute.DeveloperInfo("C# 개발자", Date="11-11-2000")]
public class AttTest

{

    ...
}


[AdditionalInfoAttribute(“jclee”,”2004-01-01”, Download=http://www.oraclejava.co.kr)]
[AdditionalInfoAttribute(“tatata”,”2004-02-01”, Download=http://www.oraclejava.co.kr)]
class OracleJava { … }

 

3.2 어셈블리관련 어트리뷰트

using절 다음에 위치하며 어떤 code 보다 앞에 존재해야 한다. 어셈블리의 어트리뷰트임을 명시(assembly:)한다.

using System.Reflection;

[assembly: AssemblyTitle("C# How-To: Multithreading")]
[assembly: AssemblyDescription("Microsoft C# .NET How-To: Multithreading")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("Microsoft C# .NET How To: 2002")]
[assembly: AssemblyCopyright("Copyright  2002 Microsoft Corporation.  All rights reserved.")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyVersion("1.0.0.0")]
 

 

 3.3 기타 어트리뷰트 사용 예

 

[WebService(Namespace = "http://www.abcworld.or.kr/DssWeb")]
[WebServiceBinding(Name = "LocalBinding", ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Main : System.Web.Services.WebService
{
       //
}

 

[WebMethod(Description = "SQL구분자와 2개의 문자열 파라미터를 받고 DataTable 로 리턴함.",

                   EnableSession = true)]
public DataTable Get2PamTbl(String QryTitle, String strStdDate, String strEndDate)
{
       // String UserIP = (String)Session["UserIP"];
}

 


[Serializable]  클래스가 serialize될 수 있음을 나타냅니다.
Serialization(직렬화):직렬화는 객체를 저장매체(파일이나 메모리와 같은)에 저장하거나 바이너리(이진) 형태로 네트워크를 통해 전달하기 위해 저장하는 과정이다. 이(객체를 직렬화한) 연속된 바이트나 포맷은 다시 원래 객체가 가지고 있던 상태로 객체를 재생성하는데 사용할 수 있다. 이렇게 객체를 직렬화하는 과정은 디플레이팅(deflating) 또는 마샬링(marshalling)이라고도 부른다. 직렬화와는 반대로 연속된 바이트로부터 어떤 데이터 구조를 추출해내는 과정을 역직렬화(deserialization)라고 한다. 역직렬화는 인플레이팅(inflating) 또는 언마샬링(unmarshalling)이라 불리기도 한다.

 

 

 

 

 

 

4. 사용자정의 Attribute

 

4.1 Custom  Attribute 정의

   어트리뷰트 역시 클래스라고 도입부에 이야기했다. 사용자 정의 어트리뷰트를 만든다는 것은 결국 새 클래스를 만든다는 것이다. 클래스 선언 방법은 보통 클래스 선언하는 것과 동일한 방법으로 선언하고 다만 System.Attribute로 부터 상속을 받으면 그 클래스가 어트리뷰트가 된다. 일반 클래스와 구별하기 위해 클래스 이름 뒤에 접미사로 ‘Attribute’를 붙이는 것이 좋다. 어트리뷰트도 하나의 클래스이므로 생성자나 멤버변수(필드), 메소드등을 가질수 있으며 상속도 가능하다. 어트리뷰트 또한 일반적인 클래스처럼 생성자가 명시적으로 써주지 않아도 컴파일러에 의해 묵시적으로 디폴트 생성자를 가질 수 있다.

 

4.1.1 어트리뷰트의 범위 지정

Conditional Attribte는 메서드에만 붙일 수 있다. 마찬가지로 사용자 정의 어트리뷰트도 특정한 타겟을 지정할 수 있다.

AttributeUsage 라는 어트리뷰트를 사용하여 사용자가 정의한 데이터 타입에만 어트리뷰트를 붙일 수 있다. AttributeUsage의 파라미터는 System.AttributeTargets enum 타입으로 정의 되어 있다. AttrbuteTargets.All, AttrbuteTargets.Class, AttrbuteTargets.Delegate, AttrbuteTargets.Interface, AttrbuteTargets.Propert, AttrbuteTargets.Construct 등이 있으며 여러 개의 데이터 형에 붙일려면 ‘|’를 이용하면 된다.


[AttributeUsage(AttrbuteTargets.Method)]
public class AdditionalInfo { … }
[AttributeUsage(AttrbuteTargets.Interface | AttrbuteTargets.Delegate)]
public class AdditionalInfo { … }

 

 

 

4.1.2 어트리뷰트 예제

클래스, Enum, 구조체에 대해서 작성자, 작성일자를 표시하는 Custom 어트리뷰트다. AttributeUsage 어트리뷰트를 사용하여 적용할 타입을 지정하고 있으며 AllowMultiple 속성을 이용하여 같은 어트리뷰트를 반복 사용이 가능하도록 했다. 클래스 명을 DeveloperInfoAttribute로 주었는데 일반클래스와 구분하기 위해 접미사 Attribute를 사용하였다. 또한 System.Attribute 클래스를 상속하고 있다. 생성자에서 한개의 파라미터를 받고 있으므로 어트리뷰트를 사용할 때는 필수파라미터로 적용된다.

 

using System;

namespace CustomAttribute
{

    /// <summary>
    ///    이 클래스는 커스텀어트리뷰트의 예입니다.
    ///    클래스, Enum, 구조체를 타겟으로 작성자(개발자) 정보를 표시합니다.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Struct, AllowMultiple = true)]
    public class DeveloperInfoAttribute : System.Attribute
    {
        private string developerName;
        private string dateCreated;

        // 생성자 : 개발자명을 유일한 필수파라미터로 가지고 있음
        // 따라서 이 attribute의 필수 인수는 하나
        public DeveloperInfoAttribute(string developerName)
        {
            this.developerName = developerName;
        }

        // 작성자 명을 리턴하는 속성(Property)
        public string Developer
        {
            get
            {
                return developerName;
            }
        }

        // 작성일자를 세팅하거나 리턴하는 속성(Property)
        // 이 attribute의 선택적 인수
        public string Date
        {
            get
            {
                return dateCreated;
            }

            set
            {
                dateCreated = value;
            }
        }
    }
}

 

 

 

4.2.1  Custom  Attribute 사용

[CustomAttribute.DeveloperInfo("한개발", Date="12-12-2000"),
 CustomAttribute.DeveloperInfo("C# 개발자", Date="11-11-2000")]
public class AttTest

{
    [CustomAttribute.DeveloperInfo("고성능")]
    public enum DaysOfWeek
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }

    [CustomAttribute.DeveloperInfo("이로직")]
    public struct Book
    {
        public string author;
        public string title;
        public int copyright;

        public Book(string a, string t, int c)
        {
            author = a;
            title = t;
            copyright = c;
        }
    }

}

 

 

 4.2.2 사용자정의 어트리뷰트의 처리 과정

   - 어트리뷰트 클래스를 찾는다.
   - 어트리뷰트의 범위를 체크 한다.
   - 어트리뷰트의 생성자를 체크 한다.
   - 객체의 인스턴스를 생성 한다.
   - 명명 파라미터들을 체크 한다.
   - 명명 파라미터 값으로 필드나 프로퍼티의 값을 설정 한다.
   - 어트리뷰트 클래스의 현재 상태를 저장한다.

 
 

 

4.3   Custom  Attribute 맴버확인

클 래스에 어트리뷰트를 붙였다면 반대로 클래스로부터 어떤 어트리뷰트들이 붙어 있는지 아는 하는 방법도 있어야 할 것이다. 바로 전 예제에서 Test라는 클래스에 어트리뷰트를 붙였는데 반대로 Test라는 클래스로부터 어트리뷰트 정보를 알아내는 방법을 예제를 통해 보도록 하자.

 

4.3.1 클래스 메타 데이터
여 기서는 Reflection을 이용하여 값을 얻어오는 것을 살펴 보도록 하자. 닷넷 프레임 웍에서는 메타데이터를 검사 할 수 있는 클래스들이 포함된 System.Reflection 이라는 네임스페이스를 제공 하고 있다. 이 Reflection 네임스페이스 안에 있는 MemberInfo 라는 클래스는 클래스의 어트리뷰트를 알아볼 때 유용하게 사용 될 수 있다. System.Type 객체의 GetMembers 라는 메소드를 적절히 구사하여 클래스 메타데이터 를 조사 할 수 있다.


System.Reflection.MemberInfo[] members;
Members = typeof(MyClass).GetMembers();

 


4.3.2 어트리뷰트의 정보 얻기
MemberInfo 객체는 GetCustomAttributes 라는 메소드를 가지고 있다. 이 메소드는 모든 어트리뷰트의 정보를 배열로 알아 낼 수 있다. 이렇게 알아낸 정보를 반복문을 이용하여  어트리뷰트를 조사 할 수 있다.

 

    public static void Main()
    {
        System.Reflection.MemberInfo attrInfo;
        attrInfo = typeof(AttTest);
        object[] attrs = attrInfo.GetCustomAttributes(false);

        CustomAttribute.DeveloperInfoAttribute developerAttr;
        developerAttr = (CustomAttribute.DeveloperInfoAttribute)attrs[0];
        Console.WriteLine("개발자: {0}\t작성일: {1}", developerAttr.Developer, developerAttr.Date);
        developerAttr = (CustomAttribute.DeveloperInfoAttribute)attrs[1];
        Console.WriteLine("개발자: {0}\t작성일: {1}", developerAttr.Developer, developerAttr.Date);


        Console.WriteLine(" \t\t");

        foreach (Attribute attr in attrInfo.GetCustomAttributes(true))
        {
            CustomAttribute.DeveloperInfoAttribute info = attr as CustomAttribute.DeveloperInfoAttribute;

            if (info != null)
            {
                Console.WriteLine("개발자: {0}     작성일: {1} \t", info.Developer, info.Date);
            }
        }

        Console.ReadLine();
    }

반응형

+ Recent posts