메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

VB.NET의 새로운 기능 - Generics

한빛미디어

|

2004-06-07

|

by HANBIT

11,497

저자: Wei-Meng Lee, 한동훈(traxacun @ unitel.co.kr) 역

원문기사: http://www.ondotnet.com/pub/a/dotnet/2004/05/25/whidbey_vbnet_pt2.html

닷넷 프레임워크 2.0(.NET Framework 2.0)의 새로운 특징은 IL(Intermediate Language)에서 제네릭(Generics)을 지원한다는 점입니다. IL에서 이러한 기능을 지원함에 따라 C#과 VB.NET에서도 제네릭을 사용할 수 있습니다. C#에서 제네릭에 대한 이야기는 많이 들어봤을 테지만 VB.NET에서의 제네릭에 대해서는 거의 얘기를 듣지 못했을 것입니다.(제네릭은 IL의 특징이므로 C# 고유의 특징이 아닙니다) 그래서 여기서는 VB.NET 프로그래머들에게 제네릭을 소개할 것입니다.

제네릭 소개

제네릭이 어떻게 동작하는지 알아보기 위해 예제를 살펴보겠습니다. 스택 클래스를 구현해야 한다고 합시다. 스택이란 LIFO(Last-In-First-Out) 자료구조이며, 스택에 데이터를 넣을 수 있고, 꺼내올 수 있습니다. 이에 대한 구현은 다음과 같습니다.

Public Class MyStack
   Private element() As Integer " create a dynamic array
   Private pointer As Integer

   Public Sub New(ByVal size As Integer)
      ReDim element(size - 1)
      pointer = 0
   End Sub

   Public Sub Push(ByVal item As Integer)
      If pointer > UBound(element) Then
         Throw New Exception("Stack is full.")
      End If
      element(pointer) = item
      pointer += 1
   End Sub

   Public Function Pop() As Integer
      pointer -= 1
      If pointer < 0 Then
         Throw New Exception("Stack is empty.")
      End If
      Return element(pointer)
   End Function
End Class

위에서 구현한 Stack 클래스는 정수형식(Integer)만 사용할 수 있습니다. 원한다면 다른 데이터 형식을 위한 구현도 가능합니다. 예를 들어, String이라면 String 형식만 사용하도록 변경하여 구현하면 됩니다. 이것은 융통성있는 클래스 정의 방법은 아닙니다.

이러한 문제를 해결하는 한 가지 방법은 Object 데이터 형식을 사용하여 컴파일러가 데이터 형식을 나중에 결정하는 후기 바인딩(late-binding)을 사용하는 것입니다.(변경된 부분만 굵게 표시했습니다)

Public Class MyStack
   Private element() As Object " 후기 바인딩을 위해 Object 형식을 사용
   Private pointer As Integer
   Public Sub New(ByVal size As Integer)
      ReDim element(size - 1)
      pointer = 0
   End Sub
   Public Sub Push(ByVal item As Object)
      If pointer > UBound(element) Then
         Throw New Exception("Stack is full.")
      End If
      element(pointer) = item
      pointer += 1
   End Sub

   Public Function Pop() As Object
      pointer -= 1
      If pointer < 0 Then
         Throw New Exception("Stack is empty.")
      End If
      Return element(pointer)
   End Function
End Class

다양한 데이터 형식에 대해 사용할 수 있게 Object 형식을 이용한 접근 방법은 Stack 클래스를 사용할 때 적절하지 못한 데이터 형식을 “집어 넣을 수(Push)”있다는 점입니다. 굵게 표시한 부분을 보세요.

Dim stackC As New MyStack(2)
stackC.Push(5)
stackC.Push("A")
Dim val1, val2 As Integer
val1 = stackC.pop    "runtime error here

그러나, 이런 실수는 프로그램을 실행중에만 발견됩니다. 예를 들어, 문자열 값을 꺼내오고(Pop) 그 값을 정수 변수에 할당하려하는 경우입니다.
VB.NET에서 제네릭으로 알려진 새로운 형식이 지원됩니다. 제네릭을 사용하면 Stack 클래스에서 사용될 데이터 형식을 수정할 필요가 없습니다. 대신에 새로운 키워드 Of를 사용합니다. Of 키워드는 클래스, 구조체, 인터페이스, 대리자(delegate), 프로시저에서 데이터 형식 인자를 가리킵니다. 제네릭 사용법을 알아보기 위해 스택 클래스를 다음과 같이 재작성했습니다.

Public Class MyStack(Of itemType)
   Private element() As itemType " 동적 배열 생성
   Private pointer As Integer

   Public Sub New(ByVal size As Integer)
      ReDim element(size - 1)
      pointer = 0
   End Sub

   Public Sub Push(ByVal item As itemType)
      If pointer > UBound(element) Then
         Throw New Exception("Stack is full.")
      End If
      element(pointer) = item
      pointer += 1
   End Sub

   Public Function Pop() As itemType
      pointer -= 1
      If pointer < 0 Then
         Throw New Exception("Stack is empty.")
      End If
      Return element(pointer)
   End Function
End Class

굵은 글씨로 강조된 부분에서 알 수 있는 것처럼 데이터 형식을 정의해야할 자리에 itemType이라는 이름을 사용했습니다. 즉, 이 클래스를 디자인하는 동안에는 Stack 클래스에서 사용할 데이터 형식을 지정하지 않습니다.

Stack 클래스에서 정수(Integer)를 다루게 하고 싶다면 인스턴스 생성시에 다음과 같이 정의하면 됩니다.

Dim stackA As New MyStack(Of Integer)(2)
" the itemType will now be replaced by the Integer
stackA.Push(5)
stackA.Push(6)
stackA.Push("Some string...") " 컴파일 에러(compile-time error)
MsgBox(stackA.pop)
MsgBox(stackA.pop)
MsgBox(stackA.pop)

세번째 Push() 메서드에서 컴파일 에러가 발생합니다. 즉, 컴파일 시간 동안 Stack 클래스에서 사용할 데이터 형식을 컴파일러가 점검하게 되며, 에러를 발견합니다. 이것은 VB.NET에서 제네릭을 사용할 때 얻을 수 있는 이점입니다.

String 데이터 형식에 대해서 Stack 클래스를 사용하고 싶다면 다음과 같이 하면 됩니다.

Dim stackB As New MyStack(Of String)(3)
stackB.Push("Generics")
stackB.Push("supports ")
stackB.Push("VB.NET ")
MsgBox(stackB.pop)
MsgBox(stackB.pop)
MsgBox(stackB.pop)

제네릭의 장점

앞 절에서 논의한 것처럼 제네릭을 사용할 때 다음과 이점을 알아내는 것은 그리 어렵지 않습니다.
  • 형 안정성(Type Safety) - 제네릭 타임은 응용 프로그램 실행중이 아닌 컴파일중에 데이터 형을 검사합니다. 이로 인해 실행 중에 데이터 형식 충돌 가능성을 줄여줍니다.
  • 수행성능 - 제네릭 클래스에서 사용하는 데이터 형식은 컴파일 시에 결정되기 때문에 형변환(type casting)이 필요하지 않으며, 그에 따른 비용을 절약할 수 있습니다.
  • 코드 재사용 - 하나의 클래스를 작성하는 것으로 다양한 데이터 형에 대해서 사용할 수 있으므로 코드 재사용량이 증가합니다.

용어

그림1은 제네릭 형식에서 사용하는 용어들을 설명합니다.



그림1. 제네릭 용어

제네릭 타입의 제약조건

제네릭 타입에 제약조건을 사용할 수 있습니다. 예를 들어, Stack 클래스에 특정 형식의 객체만 조작할 수 있게 할 수 있습니다. 예를 들어, Employee 형식만 사용하게 하려면 제네릭 타입을 다음과 같이 선언할 수 있습니다.

Public Class MyStack(Of itemType As Employee)

제네릭 타입에는 제약 조건을 여러 개 사용하는 것도 가능합니다. 복수의 제약 조건을 적용하려면 {type1, type2, ..., typeN }과 같이 사용하면 됩니다. 예를 들어, Stack 클래스에 Employee와 IComparable 인터페이스 형식의 객체만 조작하고 싶다면 제네릭 타입을 다음과 같이 선언할 수 있습니다.

Public Class MyStack(Of itemType As {Employee, IComparable})

제네릭 제약조건 사용을 설명하기 위해 클래스 정의를 다음과 같이 했다고 하겠습니다.

Public Class Employee
   Implements IComparable
   Public employeeID As String
   Public name As String
   Public Function CompareTo(ByVal obj As Object) As Integer _
    Implements System.IComparable.CompareTo
      " add code here
   End Function
End Class

Public Class Manager
   Inherits Employee
   ...
End Class

Public Class Programmer
   Inherits Employee
   ...
End Class

다음 구문은 모두 사용가능합니다.

Dim stackD As New MyStack(Of Programmer)(3)
Dim stackE As New MyStack(Of Employee)(3)
Dim stackF As New MyStack(Of Manager)(3)

요약

제네릭은 클래스를 작성하기 위한 향상된 방법입니다. 제네릭을 사용함으로써 코드는 보다 단순해지며 이해하기 쉬워지고, 보다 효율적이며, 무엇보다도 더 안전해집니다.
TAG :
댓글 입력
자료실

최근 본 책0