저자: 사티야 코마티네니(Satya Komatineni), 역 한동훈
닷넷 프레임워크에서는 코드에 대한 주석을 달기 위해 특성(attribute)을 광범위하게 사용한다. 예를 들어 XML 순차화(serialization)는 클래스를 순차화하는 방법을 다루기 위해 특성을 사용한다. 실제로 특성이 관리 클래스(managed class)라는 것을 모른다면 특성의 구문이 이상해 보일 것이다. 본 기사에서는 특성 구문에 대해 간략하게 살펴보고 특성을 읽는 방법과 실제 프로그래밍에서 특성을 정의하기 위해 문서를 참조하는 것에 대해서 살펴볼 것이다.
닷넷에서 특성은 다양한 곳에 사용되고 있다. 특성이 중요하고 필수적인 역할을 하는 XML 순차화 예제를 살펴보자. 이 예제에서는 C# 클래스를 디자인하고 이 클래스를 XML로 순차화할 것이다. 클래스 정의는 다음과 같다.
Public class MyClass
{
public string myField = "abc";
}
위 클래스는 다음 코드를 사용하여 XML로 스트리밍 할 수 있다.
MyClass myObject = new MyClass;
XmlSerializer xs = new XmlSerializer(typeof(myObject));
StringWriter sw = new StringWriter();
Xs.serialze(sw,myObject);
위 코드에서 생성된 XML은 다음과 같다.
abc
생성된 XML이 어떻게 되는지 살펴보도록 하자.
[XmlRoot("MyXmlClass")]
Public class MyClass
{
[XmlElement(ElementName="myXmlField")]
public string myField = "abc";
}
여기서 생성된 XML은 다음과 같다.
abc
XML 순차화에는 순차화 과정을 제어할 수 있는 많은 특성들이 있다. 이들 특성에 대해서는 본 기사를 정리하면서 참고자료에 소개해 놓겠다. 여기서는 2개의 특성만 논의할 것이다.
필자가 이러한 특성들과 부딪쳤을 때의 첫 느낌은 ‘이 특성 정보를 어떻게 읽고 이해해야 하는가’라는 문제였다. "
[XmlRoot("somename")]"의 의미는 무엇인가? 프로그래머가 XML의 루트 노드의 이름을 설정하려 한다는 것은 쉽게 예상할 수 있었겠지만 구문이 명확한 것은 아니다. 여기서는 인용부호 안에 직접 문자열을 지정했지만 다른 경우에는 어떤 다른 종류의 키를 사용하여 문자열을 설정할 수 있다.
경우에 따라서는 여러 가지 특성들을 분리하기 위해 콤마를 사용할 수도 있고, 특성을 여러 번 사용할 수도 있다. 경우에 따라 같은 특성을 반복할 수도 있고, 그렇지 않을 수도 있다. 특성은 필드나 클래스에 적용할 수도 있기 때문에 일관되지 않은 규칙을 갖고 있는 것처럼 보인다.
그러나 특성을 읽을 수 있는 방법이 있다. 특성을 이해하는 핵심은 특성이 닷넷 클래스를 나타낸다는 것이다. 특성들이 실제로 클래스라는 관점에서 살펴보자.
- 특성(attribute)은 클래스다. 특성을 지정하는 것은 실제로 닷넷에서 그 특성에 해당하는 클래스의 인스턴스를 생성하는 것이다. 이 때문에 특성을 정의하는 것은 클래스 생성자 구문과 비슷하다. 이러한 생성자의 모든 인자는 정적(static)이며 컴파일 시간에 지정된다.
- 특성 이름은 클래스 이름이다. 특성이 클래스이므로 특성의 이름은 클래스 이름이 된다. 클래스 이름은 네임 스페이스를 포함하며 특성 이름도 포함한다. 그렇다면 XmlRoot는 어떤 클래스를 나타내는 것인가? XmlRoot는 실제로 System.Xml.Serialization.XmlRootAttribute의 축약형이다. 나중에 이렇게 긴 이름을 어떻게 XmlRoot로 줄일 수 있는지 보여주겠다.
- 특성은 네임 스페이스를 사용한다. 특성은 클래스이므로 특성을 정의한 네임 스페이스를 포함하려면 "using" 구문을 사용해야 된다. 따라서 위의 경우에는 System.Xml.Serialization 네임 스페이스를 임포팅 한 후, XmlRootAttribute처럼 이름을 줄일 수 있다.
- 특성은 클래스와 마찬가지로 여러 개의 생성자를 가진다. 특성 정의는 생성자와 동일하므로 특성의 괄호안에 사용하는 것은 클래스의 생성자에 전달하는 인자가 있다. 다른 관리 클래스와 마찬가지로 특성은 다양한 생성자를 가질 수 있다. 실제로, 관리 클래스와 마찬가지로 생성자를 지정하지 않으면 특성 이름을 지정하면 된다.
- 특성의 생성자는 클래스의 생성자보다 더 많을 것을 할 수 있다. 위 생성 규칙에도 예외는 있다. 특성은 클래스를 구성하는 것 뿐만 아니라 public 속성들도 설정할 수 있다. 클래스에 public 속성이 있다면 이들 속성을 설정할 수 있는 방법이 필요하다. 생성 구문은 속성을 설정할 수 있도록 확장되어야 하며, Public 속성들은 키와 값의 조합으로 된 구문을 사용하는 인자를 사용하여 지정할 수 있다.
- 특성 생성자 구문은 다양한 형태를 가질 수 있다. 특성은 다양한 형태를 가지며 이들은 모두 생성자와 public 속성을 설정한다. 특성을 지정하고 생성자의 인자 다음에 public 속성을 부가적으로 설정할 수 있다.
- 특성 문서화를 참조하는 방법. 특성도 클래스이므로 다른 관리 클래스와 마찬가지로 문서화를 사용할 수 있다. 생성자의 인자를 참조하고, 특성 클래스의 public 속성을 참조할 수 있다. 특성 문서화는 특성이 적용되는 곳에 프로그래밍에 대한 개념을 적용할 수 있다.
- 특성의 public 속성 다루기. 특성 클래스의 public 속성은 생성자에 사용하는 필수 인자 다음에 키와 값의 조합을 사용하여 설정한다.
- 특성을 지정할 수 있는 여러 가지 형식. 특성을 사용할 때 어려운 점은 특성을 정의하는 구문이 다양하다는 것이다. 특성을 정의하면서 일반적인 사용 패턴을 살펴보자.
사용예
[namespace.attributeNameAttribute](arg1,arg2,param1=value,param2=value);
[attributeNameAttribute](arg1,arg2,param1=value,param2=value);
[attributeName](arg1,arg2,param1=value,param2=value);
첫 번째 라인의 형식은 특성에 대한 전체 클래스 이름을 지정하고, 생성자 인자 다음에 public 속성을 쓴다. 두 번째 줄은 전체 클래스 이름에서 네임 스페이스를 생략한 것이며 세 번째는 클래스 이름에서 Attribute 접미어를 생략한 것이다. 세 번째 방법은 완전히 프로그래밍 편의를 위한 것으로 이들 변형을 설명하는 몇 가지 예제를 살펴볼 것이다.
특성 예제
1. [System.Xml.Serialization.XmlRootAttribute(ElementName="LOAD_TENDER_TRIP",
Namespace="", IsNullable=false)]
2. [System.Xml.Serialization.XmlRootAttribute("LOAD_TENDER_TRIP",
Namespace="", IsNullable=false)]
3. [XmlRootAttribute(ElementName="LOAD_TENDER_TRIP",
Namespace="", IsNullable=false)]
4. [XmlRoot(ElementName="LOAD_TENDER_TRIP", Namespace="", IsNullable=false)]
1은 특성에서 기본 생성자를 사용하고 세 개의 public 속성을 지정하고 있기 때문에 허용된다.
2는 특성에서 인자를 하나 가지는 생성자를 사용하며, 같은 줄에 public 속성을 두 개 사용한다.
3은 클래스의 네임 스페이스가 생략되었으므로 using System.Xml.Serialization을 사용하여 네임 스페이스를 임포트해야 한다.
4는 Attribute 접미어를 생략한 것이다.
특성 지정 규칙
특성에 적용되는 규칙은 다음과 같이 요약할 수 있다.
- 특성은 []안에 사용하며 그 안에 속한 프로그래밍 구조 위에 바로 써야 한다.
- 관례적으로 모든 특성 클래스들은 이름 뒤에 Attribute를 붙인다.
- 특성 이름은 특성 클래스의 이름이 되며, 규칙 2에서 하는 것처럼 Attribute를 생략할 수 있다.
- 네임스페이스를 임포트하면 특성 이름에서 네임스페이스를 생략한 것을 사용할 수 있다. 네임스페이스를 임포트하면 클래스 이름에서 네임스페이스를 생략하는 것과 비슷하다.
- 접미어 Attribute는 특성을 지정할 때 생략할 수 있다. 닷넷은 클래스에 이 접미어를 추가할 수 있다. 원본 클래스에 Attribute 접미어가 없다면 지정된 이름으로 클래스를 찾는다.
- 특성을 여러 개 정의하기 위해 특성을 쌓을 수 있다.
[attribute1()]
[attribute2()]
- 특성들은 []안에서 콤마(,)로 구분하여 나열할 수 있다.
[attribute1(), attribute2()
- 몇몇 특성들은 인스턴스를 여러 개 생성할 수 있지만 어떤 것들은 그렇지 않다. 인스턴스를 여러 개 생성할 수 없는 특성을 반복해서 사용하면 컴파일러는 에러를 발생시킨다.
- 생성자 인자들 다음에 부가적으로 public 속성을 사용할 수 있다. 기본 생성자를 사용한다면 특성에서 ()를 생략할 수 있다. 예를 들면 다음과 같다.
[attribute1]
- IDE는 해당 특성 클래스에 대한 적절한 도움말 섹션으로 이동하는 방법을 알고 있으며 이는 특성 이름에 Attribute나 Namespace가 지정되지 않은 단축된 형태일 때도 적용된다.
참고자료
- 특성에 대한 완벽한 레퍼런스로 활용가능한 기사: Programming C#: Attributes and Reflection
- .NET Framework Developers Guide의 "Attributes that Control XML Serialization"에서는 XML 순차화에서 사용하는 XML 특성들의 완전한 목록을 제공한다.
- .NET Framework Developers Guide의 "Controlling XML Serialization using Attributes"에서는 XML의 일리먼트들을 배열이나 컬렉션 등으로 순차화하기 위해 이들 특성을 사용하여 효율적으로 처리하는 과정에 대해서 잘 설명하고 있다.
- 11월 출간예정도서 『.NET and XML』
본 기사의 저자인 사티야 코마티네니(Satya Komatineni)는 Indent, Inc의 CTO이며 J2EE/XML을 위한 오픈 소스 웹 개발 도구인 Aspire의 저작자이다.