삽질의 현장/- .NET

#074_닷넷(.NET)_.Net Framework 기본 - 특성 (Attribute)

shovelman 2015. 11. 11. 20:13


안녕하세요 삽잡이입니다.


이번 시간에는 닷넷에서 제공하는 특성에 대해서 알아보려고합니다.


특성은 우리가 알고 있는 특성이 아닙니다.



닷넷에서 말하는 특성인 필드를 말하는 것이 아닙니다.



XML의 Element를 가보면, 시작태그와 끝 태그가 있다고 하지 않았습니까?

그 사이에 시작 태그의 이름과 값 사이에 있는 특성을 말하는 것도 아닙니다.


제가 이번 시간에 말하고자 하는 특성은 

닷넷에 있는 또 다른 특성입니다.



우선 C#에서 기호로는 대괄호 내에 있는 어떤 것을 바로 '특성'이라고 부릅니다.


이 특성은 어셈블리 자체에 특성이 있을 수도 있고,

그 외에 모듈, 타입, 멤버(속성, 필드, 메서드 등)등에 지정될 수 있는 특성들이 있습니다.

즉, 특성이라는 것이 그런 것입니다.

어셈블리, 모듈, 타입, 멤버등에 지정될 수 있는 것이죠.

이러한 것들에 부여되는 특성을 가리켜서 attribute라고 부릅니다.


특성을 부여해주는 것이라고 생각하시면 됩니다.

어셈블리가 가지고 있는 특성을 부여한다던지, 

타입이 가져야하는 특성을 표현하던지 말입니다.


원래 특성이라는 것은 존재하지 않았었습니다.

후에 추가된 문법이라는 것입니다.


OOP와 같이 AOP라는 관점 지향 프로그램 개념에서 

받아들인 개념이 바로 특성이란 개념입니다.

AOP는 또한, 횡단형 프로그램이라고도 합니다.



이 횡단형 프로그램이란,

본질적인 코드가 있고, 특성을 부여해줄 수 있는 프로그램을 말하는 것입니다.


원 코드가 있는데 [A]를 하냐, [B]를 하냐, 혹은 [A, B]를 하냐에 따라

원 코드에서 특성이 추가되는 것이죠.


이러한 특성의 장점으로는, 

빼고 싶으면 쉽게 빼고, 추가하고 싶으면 쉽게 추가할 수 있다는 것입니다.

즉, 특성을 부여했다가 뺐다가하는 것이 간단하다는 소리입니다.


왜 이게 그런데 횡단형일까요?

원 코드에 A라는 특성을 부여하면 A특성을 갖는 코드가 되지 않습니까?

즉, 코드는 하나인데 부여하는 특성에 따라서 코드가 된다 이겁니다.

그래서 횡단형 프로그램이라고 하고, 관점 지향이라고도 부르는 것입니다.


기존에 '딱! A에 대해서 동작하구나!' 라는 

이러한 코드의 개념을 갖고 있었다는 것입니다.

해당 개념을 받아들여서 닷넷에서 특성이 만들어진것이죠.


역으로 생각해보겠습니다.

만약, 코드가 어떤 타입이라고 생각해봅시다.

이 타입에 필드를 두면 되지 않을까요?

과연 필드로 가지는 것이랑 어떤 차이가 있을까요?


완전 달라 ㅋ  



허허... 완전 다릅니다.

예를 들어 필드를 색상으로 하게 된다면 본질 적인 코드가 되어버립니다.

이 색상은 필드로써 코드를 가지면 클라이언트 코드에서 결정하게 되어버리는 것이지요.

즉, 본질적으로 코드가 장착되어 있기 때문에 뺄 수가 없습니다.


이러한 이유로 특성이 도입된 것입니다.

특성이 왜 쓰이는지가 중요합니다.




메서드로 따져볼까요?

Print()라는 메서드가 하나 있다고 해봅시다.

이는 아무 속성이 부여되지 않은 주요 코드로써,

주요 기능은 어떤 '출력'을 하는 코드일 뿐입니다.


그런데 여기에 직렬화, 동기화와 같은 특성을 부여해준다고 해보겠습니다.

동기화를 특성으로 부여할 경우 기존의 출력하는 코드는 유지가 되지만

해당 메서드를 호출하는 모든 쓰레드는 동기화 작업을 하게 될 것입니다.

세마포어, 뮤텍스 이런 것 필요 없이 말입니다!


기본적으로는 단지 Print() 메서드일 뿐이지만,

'동기화' 특성을 부여함으로써 어떤 쓰레드에 의해서 호출되던지

딱 하나의 쓰레드만이 메서드를 수행하는 동기화 가능한 쓰레드가 되더라 이겁니다.


또한, 직렬화 기능을 넣으면

기존의 Print() 메서드가 호출되어 기능을 하고 파일에 직렬화도 가능해진다 이겁니다.


뭔가 감이 오십니까?

특성과 본질적인 코드는 다릅니다.

Print와 직렬화, 동기화 이런 것이 관련이 있습니까?

Print는 단지, 출력을 하겠다는 개념을 가지고 있는 메서드입니다.


그런데, 여기에 속성을 부여하게 되면,

동기화 가능한 Print(), 직렬화 가능한 Print() 가 된다 이겁니다.


이런 개념이 가능한 프로그램이 제공되게 되면,

굉장히 유용해진다는 사실을 발견했습니다.

그리고 이런 개념이 바로 AOP 프로그램 방식이었고 말입니다.

굉장히 사용해봤을 때 편했기 때문에 닷넷에서 특성이라는 문법으로 사용한다 이거죠.


멀쩡한 코드들이 있는데, IDE와 약속을 한다고 해봅시다.

어떠한 코드던지 Visual Studio를 사용하던, 이클립스를 사용하던, 

메모장을 사용하던 한 IDE와만 약속을 했는데

만약, 코드가 수정이 된다면 

한 IDE만 동작하고 다른 IDE에서는 동작한다는 보장을 할 수 있습니까?


따라서, 특성만 부여해주는 것입니다.

그렇게 되면 코드를 수정할 필요가 없게되니깐 말입니다.

그러니까 본질적인 코드와는 전혀 상관이 특성만을 통해 약속을 한다 이겁니다.


특성을 사용할 경우가 많다고 보장은 할 수 없으나,

분명 유용한 기능임에는 틀림없습니다.


프로그램 하나를 실행하고 난 뒤에 만들 때에는 유용할 듯했지만, 

나중에 해당 기능이 필요가 없어졌다고 해봅시다.

이때 쉽게 기능을 그냥 제거해버리면 될까요?

안됩니다.. 왜냐, 이전 버전들은 해당 기능을 사용할 수 도 있기 때문입니다.


그러면 어떻게 할까요.. 버리지도 못하고...

이럴 때도 ignore라는 특성을 사용하면 유용합니다. 권장을 하는 것이죠...

'이런 기능이 더 좋은데 이 기능을 쓰는게 어때?'

이런식으로 말입니다. 허허..


그리고 해당 기능에는 ignore 표식을 해두는 것이죠...

즉, AOP 기반에 ignore 특성이 달려있다 이겁니다.

닷넷에는 당연히 '특성'이 달려있겠지요.

참고로 ignore은 닷넷에서 [Obsolete]입니다.


타입을 못쓰게 하려면 타입에 달고, 메서드를 못쓰게 하려면 메서드에 달면 됩니다.

지우지는 못하기 때문에 Editor와 대화를 하는 것이지요.

즉, 본질적인 코드는 그대로 동작해야하니,

단 하나라도 건드리지 않게 되는 것이지요. 특성만 부여하면 되니깐요!

특성이라는 개념이 없었다면 이런 일이 가능했을까요...?


특성을 사용함으로써 본질적인 코드가 아니기 때문에 

서로간에 통신 개념을 통해 주고받을 수 있게 되었다는 사실을 알 수 있게 되었습니다.


계속해서 반복하지만,

특성은 본질적인 코드와 상관이 없습니다. 그래서 굉장히 유용한 것입니다.


직렬화는 이와 같이 사용할 수 있습니다.



[Serializable] 는 자동으로 파일 입출력이 가능하도록 만들어주는 특성입니다.

그리고, [NonSerialized] 는 '이 녀석만 빼고!' 라는 뜻의 특성이지요.



특성은 또한, 여러개의 특성을 지정하는 방법도 있습니다.

만약, 아무것도 지정하지 않는다면 

기본 생성자를 통해서 특성이 생성되고,

두번째 특성처럼 생성자를 따로 호출하여 생성할 수도 있습니다.


타입위에 생성을 하군요... 이건 서로간에 약속입니다.


특성도 사실 클래스로 만들어져있습니다.

컴파일러가 특성을 부여하면 클래스의 인스턴스를 만들어줘서 

연결한다고 생각하면 됩니다.

객체와 특성을 연결짓는다고 생각하라는 것입니다.


특성의 실제 클래스는 사실 접미사로 Attribute가 들어갑니다.

그런데, 모든 특성의 실제 클래스에는 

Attribute가 생략되어 사용할 수 있습니다.

또한, System.Attribute를 상속받습니다.

사용자 특성을 만들 때에도 

Attribute를 상속받아 만들어낸다는 사실을 알 수 있습니다.


지금까지 알아본 특성에 대해서 정리를 해봅시다.


우선, 특성은 Attribute를 상속받은 클래스입니다.

그리고, 특성에 대한 정보는 메타데이터와 함께 삽입이 되고, 

특성에 대해서 읽어지기 전 즉, 알아내기 전까지는 반영이 안됩니다.

이는 주석에 불가하다는 소리입니다. 


특성을 사용하지 않는다면 아무것도 아니라는 뜻이지요...

주 코드에 영향을 주지도 않지만,

만약, 특성을 해석하고 동작하도록 만들게 되면 의미를 갖게 된다 이겁니다.

또한, C#에서의 특성은 대괄호를 통해 적용을 시킵니다.


이 특성은 수준에 맞도록 제한시킬 수 있습니다.

예를 들어서, 클래스에 어울리는 특성인데, 

메서드 혹은 필드에도 특성을 부여할 수있기 때문입니다.


이 말은 즉, 특성을 부여할 때 다 수준이 있는데, 

이 수준에 대한 제한을 구체화할 수 있다는 소리입니다.


컴파일러는 특성이라는 것만 알기 때문에

어떠한 수준에 특성을 달아도 상관을 안합니다.

그래서 더더욱 사용자가 제약을 하는 것입니다.



제약을 할 수 있는 열거형입니다.

해당 열거형에 열거되어있는 곳에만 특성을 부여할 수 있다는 것을 정리해놓은 것이지요.



따라서 제한을 하고 싶은경우 [AttributeUsage] 특성을 통해

열거형의 값들을 지정해주면 됩니다.

아무튼.. 이렇게 사용자 정의 특성이 

어디에 적용이 가능한지 지정할 수 있게 됩니다.


다시 말씀드리지만,

특성이 다양한 곳에서 사용이 되다 보니 이렇게 제한 기능을 제공해주는 것입니다.


그리고 Attribute를 알고 있을때와 모를 때 모두 

타입 정보를 얻고 속성 정보를 얻어서 

Attribute가 달려있는지 검사도 할 수 있습니다.


이번 시간은 여기까지 알아보도록 하겠습니다.


이상 삽잡이였습니다!