PROGRAMMING WORKSHOP

.Net FrameWork,VB.Net |

LINQ 시작...

집합체를 다루면서 또 다른 지능높은 도구 LINQ를 이야기할때가 되었다
정보는 떼거리로 몰려 다닌다..
이런 떼거리로 몰려다니는 정보를 보관하고 처리하기 위한 수단은
VBA에서 Array(배열)과 Collection(집합체)두개는 이미 잘 알고 있을 것이다
VB.Net에서 집합체를 다루어주는 개체들은 .Net FrameWork 의
System.Collections 네임스페이스와
System.Collections.Generic 네임스페이스 두곳이다..
그런데 왜 이렇게 두곳으로 분산되었나??
프로그래밍을 하다 보면 모듈시트를 여러게 놓고, 이 모듈시트에 있던 것을
좀더 개선하여 다른 모듈시트에 모아 놓을수 있을 것이다
그런 의미인 것이다
System.Collections 네임스페이스의 것은 이전 것이고..
System.Collections.Generic이란 네임스페이스에 좀더 개선된 집합체를
모아 놓았다고 보도록 하면 되겠지
쉽게 이야기해서 System.Collections에 있는 것은 헌것이고
Sysem.Collections.Generic쪽에 있는 것은 새것이다
가장 대표적인 것이 Array(배열)을 발전시킨 ArrayList개체가 System.Collections쪽에 있고
이것에 대응한 새것이 System.Collections.Generic쪽의 List(Of T) 라고 하는 것..
그래도 집합체의 가장 원초적인 Array(배열)도 자주 사용하는 것이니,
상황에 마추어 무엇이 좋을까, 선택하여 사용하는 것
VBA에서 배열을 사용하기도 하고, Collection개체를 사용하기도 하듯이
문제는 제공하는 것을 이왕이면 많이 알고,선택의 폭을 넓히는 것이 좋다



위의 그림은 System.Collections의 ArrayList개체와
System.Collections.Generic의 List(Of T)개체를 비교해본것이다

LINQ(Language-Integrated Query) 를 사용하는 대상이 바로 이런 집합체라는것..
Language INtegerated Query를 우리말로 옮기면 [언어에 통합되어 있는 쿼리언어]
Query는 원하는 것을 찾아오는 작업..그러니 집합체에 몰려있는 정보에서
원하는 것을 찾아주는 언어는 언어인데 언어에 통합되어있다는 것은 무슨 의미인가
예를 들면 데이타베이스에서 정보를 찾아오는 쿼리언어는 SQL이라고 하는 것이 있다
이것은 문자열로 된 정보이다..
Select table.Field1, table.Field2 From TableName Where 조건.....
와 같이 문자열로 작성하여 DataBase의 개체의 메소드에 전달하여 갖여 온다
그런데..이 문자열 언어를 작성하려면..테이블이름도, 휠드명도 어디에 적어놓고
하던가 하여야 한다, 즉 실행되기전에는 그냥 의미없는 문자열정보일뿐이다
하지만 LINQ는 작성하면서 사용하는 개체의 구성원목록(IntelliSense support)등이
아래의 그림과 같이 나타난다
숙달된 VB언어 환경에서 Query를 VB언어 작성하듯이 하면 되는 것



SQL언어 같지만 문자열정보가 아닌 VB라는 개발언어에 통합된 하나의 언어인 셈이다
또한 정보를 떼거리로 보관하는 DB에서 정보를 가져오던, XML에서 정보를 가져오던
사용자정의개체(Object)등에서 정보를 가져오던 각각 별개의 Query언어가 필요없이
하나로 통합하여 사용할수 있겠다는 아이디어인 것이다

만들어 보아야지..이해하기 쉽겠지
예를 들어서 알파벳으로된 정보가 1000개가 있다고 치자..
이속에서 첫째문자가 A인 것만 찾아내고 싶다고 치자
VBA와 배열과 Collection을 많이 사용하는 환경에서의 방법은
순환하면서 찾는 것이 상식이다

Private Sub ButtonUseTraditionalLoop_Click(sender As System.Object, e As System.EventArgs) Handles ButtonUseTraditionalLoop.Click
	Dim oList As New System.Collections.ArrayList
	Dim oRandom As New Random
	For iX As Integer = 1 To 100
		oList.Add(Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)))
	Next
	TextBox1.Text = ""
	For Each sX As String In oList
		If sX.Substring(0, 1) = "A" Then
			TextBox1.Text &= sX & vbNewLine
		End If
	Next
End Sub

위의 것을 앞 섹션에서 학습한
Lambda Expression,Delegate,LINQ를 모두 활용하는 방법으로 해보면..
물론 같은 결과이다

 Private Sub ButtonUseLinq_Click(sender As System.Object, e As System.EventArgs) Handles ButtonUseLinq.Click
        Dim oList As New System.Collections.Generic.List(Of String)
        Dim oRandom As New Random
        For ix As Integer = 1 To 100
            oList.Add(Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)))
        Next
		' LINQ로 원하는 조건에 맞는 정보찾아서 Q에 저장
        Dim Q = From X In oList
               Where X.Substring(0, 1) = "A"
               Select X
		' Q집합체를 ToArray속성으로 배열로 만든후
		' 배열개체의 ForEach 메소드에 Delegate 대신에 Lambda Expression으로 처리
        Array.ForEach(Q.ToArray, Sub(x) TextBox1.Text &= x & vbNewLine)
End Sub

위에서 Q라는 것에 LINQ의 결과를 받는데..
Q는 과연 어떤 타입의 개체인가????
아래와 같이 명시적인 개체타입을 표현해도 되고 생략해도 된다

Dim Q As IEnumerable(Of String) = From X In oList
	  Where X.Substring(0, 1) = "A"
	  Select X

또한 System.Collections.Generic의 List(Of T)는 아래와 같이
개체의 Extension Method인 WHERE를 사용하여 LINQ대신에 같은 결과를 얻을수 있다

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Dim oList As New System.Collections.Generic.List(Of String)
        Dim oRandom As New Random
        For ix As Integer = 1 To 100
            oList.Add(Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)) & Chr(oRandom.Next(65, 90)))
        Next

        '' Generic의 List(Of T)는 LINQ 대신에 메소드(Extension method) WHERE 에 Delegte(Lambda expression)을
        '' 사용할수도 있다

        Dim oQ As IEnumerable(Of String) = oList.Where(Function(x As String) x.Substring(0, 1) = "A")
        TextBox1.Text = String.Join(vbNewLine, oQ.ToArray)

End Sub

IEnumerable vs IEnumerator

위에서 LINQ의 결과를 Dim oQ As IEnumerable(Of String)과 같이 받았다
그런데 앞에 I자가 붙은 이 이상한 개체는 무엇인가??
앞에 I자가 붙은 것을 Interface라고 한다
일종의 Class(Abstract Class) 이다
Delegate와 또 다른 크래스이다
왜 이것이 필요한지에 대한 설명을 하면 점점,이야기가 꼬인다
나중에 크래스부분에서 설명할 기회를 갖도록 하고
우선 IEnumerable(Of T)는 Inteface라고 알아두자
IEnumerable(Of T)는 메소드를 딱 하나 갖고 있다
GetEnumerator 라는 메소드, 그리고 이것은 Enumerator라는 개체를 만들어주고..
이 Enumerator의 역할은
전통적인 순환(For Each X In Collection~Next)을 하면서
어떤것을 찾고 싶을때 순환대상이 되는
집합체의 정보가 모두 당연히 메모리에 올라와야 한다
그러니 아주 큰 정보를 처리하려면 메모리가 버거워진다
특히 웹으로 연결된 정보들의 처리에 있어서는 더욱..
이 부분에서 새로운 기술이 제공되는 것, 그것이 Enumerator개체인것
IEnumerable(Of T)는 단지 Enumerator개체를 만들어주는 역할을 한다
이것은 순환대상이 되는 모든 정보를 메모리에 끌어 들이지 않고
순환하면서 조건에 맞는 부분 딱 하나의 정보만 메모리로 끌어들인다
즉 효율과 속도를 개선하고자 제공되는 기술이고
VB.Net에서 제공되는 개체(집합체)들은 IEnumerable이 묵시적으로 알아서
실행이 되는 것이다, 그러니 아직은 뒤에서 벌어지는 일을 깊이 알 필요는 없다
그냥 다음에 알아야 할 대상으로 머리뒤켠에 밀어 두고..
우선 List(Of T) 혹은 ArrayList등 제공되는 개체는 IEnumerable(Of T)를
실행할수 있는 내부능력을 갖고 있다!! 라는 것을 알도록 하자!!
또한 LINQ의 결과도 IEnumerable(Of T) 라는 것도 아시고..
또 다시 말해서 LINQ는 IEnumerable 혹은 IEnumerable(Of T) 인터페이스를
지원하는 모두 집합체에 사용할수 있는 것

그래서 IEnumerble(Of T)를 지원하는(내부에서 묵시적으로 실행되는)
대표적 집합체 System.Collections.Generic.List(Of T)를 갖고
계속 이야기를 해보도록 하자

List(Of T),Object

List(Of T)라고 하면 T는 어떤 타입의 것으로 집합체를 만들수 있다는것
만약 버튼을 여러개 만들고,
여러개의 버튼을 버튼의 Text별로 정렬하는 등의 집합체작업을 하고 싶을때
Dim oListBtns As New List(Of Button) 이라고 변수를 만들면 되고,
또 버튼의 위치를 잡아 놓기 위하여 X,Y값을 떼거리로 보관하여야 하면
Dim oListOfButtons As List(Of Point)
와 같이 Point개체를 처리하면 되는 것..
아래와 같이 버튼을 만들어서 버튼의 위치를 List(Of Point)에 담는다
혹은 Type이 불분명할때는 VBA에서 Variant타입변수를 사용했듯이
VB.Net에서는 Object 타입을 사용한다
VB.Net에서는 Variant 타입은 없다
Dim oListX As List(Of Object)
와 같이 사용하면 된다

Dim oListOfButtons As List(Of Point)
Sub createButtons()
	Dim oRandom As New Random
	Dim iStartX As Integer = 3
	Dim iStartY As Integer = 3
	Dim iSize As Integer = 22
	Dim iGap As Integer = 1
	oListOfButtons = New List(Of Point)


	For iX As Integer = 0 To 9
		For iY As Integer = 0 To 6
			Dim oX As New Button
			oX.Text = Chr(oRandom.Next(65, 90))
			oX.Size = New Size(iSize, iSize)
			oX.BackColor = IIf(Int(Rnd() * 2) = 1, Color.Red, Color.Blue)
			oX.ForeColor = Color.White
			oX.Location = New Point(iStartX + iX * (iSize + iGap), iStartY + iY * (iSize + iGap))
			oListOfButtons.Add(oX.Location)
			Me.Panel1.Controls.Add(oX) ' 만든 버튼을 Panel개체에 담는다
		Next
	Next
 End Sub

위의 버튼을 알파벳값으로 주어진 Text값을 기준으로 오름차,내림차 정렬을 해보자
이것을 LINQ가 없이 한다면 순환하면서 Text값을 비교하면서
자리 바꿈을 하여야 했을 것이다



***[LOG-IN]***