Boxing





Boxint 은 묵시적으로 값 타입이 참조 타입으로 변환 하는 것을 말하는 것이고, Unboxing 은 명시적으로 참조 타입을 값 타입으로 변환 하는 것을 말한다. Boxing 이 문제가 되는 것은 변환 시에 CLR에 오버해드가 발행하는다는 점에 있다. 값 타입이 저장되는 Stack 은 CLR이 관리하는 메모리가 아니다. 하지만 값 타입이 참조 타입으로 변환 된다는 것은 참조 타입이 저장되는 Heap 으로 변환이 이루어 져야 한다는 것이고, 곧 CLR이 무언가 작업을 해줘야 하다는 것이된다. 이 점을 해결하기 위해 나온 기술이 Collection 이다.



위와 같이 ListBox 에 아이템을 추가할 때 메소드의 인자로 object 객체를 넣게 된다. 이때 int 객체를 넣게 되면 값 타입인 int 객체가 참조 객체인 object로 boxing 이 일어나다. for 루프 안이므로 boxing 작업이 늘어나므로 CLR의 오버헤드가 발생한다.







Collection



Collection 은 의미 그대로 타입의 집합이다.
Collection 은 크게 List 와 Dictionary 로 나뉜다.




List 의 사용 목적은 사용의 편리성 이다. List 의 아이템은 인덱서로 접근 할 수 있다. List 계열 컬렉션은 IList 인터페이스를 상속 받는다. List 계열에는 Array, ArrayList, StringCollection, TreenodeCollection 이 있다. List 계열은 Add, Clear, Contains, Insert IndexOf, Remove, RemoveAt 메소드를 공통으로 가지고 있다. 단, static 과 Queue 는 워낙 굳어진 사용법을 그대로 사용한다. List 계열의 컬렉션의 단점은 접근하기 위한 인덱서가 항상 유효한 것이 아니기 때문에 사용에 주의를 요한다.


ArrayList al = new ArrayList();
al.Add(button1);
al.Add(button2);
al.Add(button3);
al.Add(button4);
al.Add(button5);

Button btn = (Button)al[2];
btn.BackColor = Color.Red;

// 순환1
IEnumerator ie = al.GetEnumerator();
while (ie.MoveNext())
{
    Button b = (Button)ie.Current;  // 현재 요소
    b.BackColor = Color.Blue;
}

// 순환2 (순환1과 동일한 퍼포먼스:동일한 MSIL 생성)
foreach (Button b in al)
{
    b.BackColor = Color.Yellow;
}


al[2] 가 object 타입을 리턴한다. 우리가 원하는 것은 Button 타입이다. Button 타입은 object 타입의 자식 타입이므로 부모 타입을 자식 타입에 대입하기 위해선 타입 캐스팅을 해주어야 한다. 참조 타입간의 타입 캐스팅 이기 때문에 캐스팅 연산자를 사용해 주면 된다.



모든 컬렉션은 IEnumerable 인터페이스를 상속 받는다. IEnumerable 인터페이스는 GetEnumerator() 라는 하나의 추상 메소드를 갖는다. 따라서 해당 클래스가 GetEnumerator 메소를 가지고 있다면 그것은 컬렉션 이다. 100% 이다.!!!

GetEnumerator 메소드로 컬렉션 아이템 열거자(?)를 얻는다. MoveNext는 열거할 아이템이 있다면 True 를 리턴한다. Current 프로퍼티는 현재 요소를 리턴하되 object 타입을 리턴 하므로 적절히 형변환 해주어야 한다.






컬렉션 중에서 Dictionary 는 Search, Find 의 목적으로 사용된다. IDictionary 인터페이스를 상속 받으며, 키와 값을 동시에 설정 한다. 키는 유일하며, null 이 아닌 값을 갖는다. Dictionary 계열에는 Hashtable, DictionaryBase, SortedList 가 있다. Dictionary 계열은 Add, Clear, Contains, GetEnumerator, Remove 메소드를 공통으로 갖는다.


Hashtable ht = new Hashtable();
ht.Add("a", button1);
ht.Add("b", button2);
ht.Add("c", button3);
ht.Add("d", button4);
ht.Add("e", button5);

((Button)ht["c"]).BackColor = Color.Red;

// 제거
ht.Remove("c");

// 순환
// key, value 둘다 순환 가능
IEnumerator ie =  ht.Values.GetEnumerator();
while(ie.MoveNext())
{
    Button b = (Button)ie.Current;
    b.BackColor = Color.Blue;
}





Dictionary 계열인 Hashtable 은 컬렉션 이기 때문에 IEnumerable 인터페이스를 상속 받는다. 당연히 GetEnumerator 메소를 갖는다.








※ Collection 활용 예제



WinForm 에 하나의 ToolStrip 을 올린다.(.NET 에선 툴바 라고 하지 않고 툴 스트립 이라고 한다.)


ToolStripButton tb = (ToolStripButton)toolStrip1.Items[0];
tb.Text = "첫번째 버튼";

ToolStripTextBox tt = (ToolStripTextBox)toolStrip1.Items[1];
tt.BackColor = Color.Green;

// 동적 추가
ToolStripButton btn = new ToolStripButton();
btn.BackColor = Color.Blue;
btn.Text = "동적 추가";
btn.Name = "myButton";
toolStrip1.Items.Add(btn);
// 키로 접근
toolStrip1.Items["myButton"].Text = "변경";
// 인덱서로 접근
// toolStrip1.Items[2].Text = "변경";
// 단점 : 인덱스가 가리키는 대상이 유효성이 검증되지 않는다.


toolStrip1.Items[o] 은 ToolStripItem 을 리턴한다. ToolStripButton 은 ToolStripItem 을 상속받는다. 부모 타입이 자식 타입에 대입 해야 하므로 캐스팅 연산자를 사용하여 대입한다.

위 예제에선 toolStrip1.Items 에서 인덱서 및 키 값을 이용하여 요소를 찾았다. .NET 3.0 으로 넘어오면서 컬렉션의 List 계열과 Dictionary 계열의 사용 방법이 섞여 나오고 있다...

실행 후


Posted by six605
,