블로그 이미지
대갈장군

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2010. 9. 1. 00:10 프로그래밍/70-536
Application Domain, 줄여서 AD는 뭣하는 녀석인가? 가장 빠르고 쉽게 답하자면 '프로세스'와 비슷한 놈이다. 프로세스는 운영체제가 제공하는 일종의 '독립된 프로그램 운영 공간'인데 바로 이 AD는 .NET Framework에 의해 제공되며 운영체제가 제공하는 프로세스보다 성능 효율 그리고 보안적인 면에서 우위를 점하고 있는 놈이다.

그렇다면 이 AD가 가지는 장점을 나열해 보자.
  • 다른 어셈블리로의 직접적인 엑세스 방지 (보안성 증가)
  • 보안설정이 각각의 AD에 적용 가능 (보안성 증가)
  • 하나의 AD에서 발생한 unhandled exception은 다른 AD에 영향을 미치지 않음 (안정성 증가)
  • 프로세스 생성에 비해 오버헤드가 적다 (효율성 증가)
위에서 언급된 장점들을 이용하면 아주 효율적인 프로그램 작성이 가능한데, 두 가지의 예를 들자면, 우선 하나의 AD가 오류로 인해 정지하더라도 다른 AD 영역은 안정적으로 돌아가므로 프로그램 전체의 안정성이 증가한다. 이것을 우습게 보면 안되는 것이 인터넷 환경에서 예측할 수 없는 오류로 에러가 발생했을 경우 이 오류로 인해 저장되지 않은 모든 작업이 한번에 날아가 버린다면 얼마나 허무하겠는가? 고로 이런면에서 AD는 매우 중요한 '프로그램 안정성'을 제공할 수 있다는 것이다.

다른 예로는 효율성인데, 일반적으로 하나의 프로세스에서 돌아가는 프로그램은 모든 라이브러리 (어셈블리)가 실행시에 정적 혹은 동적으로 연결된다. 대표적인 동적 라이브러리가 DLL인데 일반적으로 이 DLL들은 사이즈가 무지막지하게 큰 경우가 있다. AD를 사용하면 이런 무거운 DLL들을 실행시에 별도의 AD 영역으로 불러들인 다음 사용하고 다시 unload 해 주면 효율성이 증대 된다. 물론 현재의 컴퓨터 환경에서 남아도는 메모리가 많은데 이렇게 까지 할 필요가 있나라는 생각이 들기도 하지만, 어쨌든, 그렇게 할 수 있다는 것은 프로세스에 비해 효율적일수 있다는 것.

Application Domain의 생성 및 어셈블리 로드, 그리고 해제에 대한 코드는 아래와 같다.

AppDomain AD = AppDomain.CreateDomain("MyDomain"); // AD 생성

AD.ExecuteAssembly("Assembly.exe"); // AD에 어셈블리 로드

AppDomain.Unload(AD); // AD 해제

위에서 말한 각각의 AD에 대한 보안 설정에 대해 자세히 알아보자. 일단 왜 개별 보안 설정이 위력적인지 알아야 한다. 예를 들어 인터넷에서 Third-party(대형 기업이 만든것이 아닌 제 삼자)가 만든 어셈블리를 사용한다고 했을때, 권한 설정이 되어 있지 않다면 이 어셈블리는 하고싶은 것을 다 할수 있게된다. 만약 이 어셈블리에 보안 취약점이 있고 해커가 그것을 이용해 사용자의 컴퓨터를 악용하려 한다고 해도 막을 방법이 없다. 사용자는 자신의 코드는 안전하다고 믿었으나 아무것도 모른체 눈뜨고 당할 수 밖에 없다. 

만약 이런 시나리오에서 '권한 설정'을 추가하게 되면 이야기가 달라진다. 새로운 AD를 설정하여 보안 취약성을 가지고 있는 어셈블리를 불러온 다음 권한 설정을 통해 하드디스크 읽고 쓰기를 금지시켜 버리면 비록 그 어셈블리가 취약성을 가지고는 있지만 악용할 수는 없게 된다.

바로 이것이 권한제한 -> 보안 취약성 제거 -> 피해 최소화 로 이어지는 방어법이다. 이것을 영어로 표현하면 Defense-in-depth 라고 하는데 위키로 찾아보니 군대 용어라고 하는데 겹겹이 방어하여 피해를 최소화하는 방어 전술이래라 뭐래라... -_- 틀린말은 아니네..

아무튼, 이런 권한 설정을 위한 방법이 바로 Evidence 인데... 책에 보니까 이 Evidence 한국말로 '증거' 에 대해서 쏼라쏼라 뭐라뭐라 많이 써놨는데 주욱 읽어보니 다 잡소리고 걍 줄여서 한마디로 '보안 등급' 정도로 생각하면 되겠다. 단계별로 생성과정을 설명하자면 우선, object[] 타입으로 생성되는 변수가 하나 있어야 하는데 이 변수는 System.Security.SecurityZone 열거자와 System.Security.Policy.Zone 객체를 사용해서 사용자가 원하는 '보안 등급 영역'을 설정할 수 있다. 대표적인 예가 SecurityZone.Internet인데 인터넷의 보안 등급 영역을 사용하라는 말이다. 인터넷 영역의 보안 등급은 당연히 매우 높음이다. 왜냐면 보안 취약성이 높기 때문이지. 아무튼, 이렇게 생성한 object[] 변수를 Evidence 객체 생성자에 때려 넣으면 비로서 Evidence 객체가 생성된다.

이제 이 생성된 Evidence 객체를 AD를 만들때 붙여 넣으면 Application Domain 전체에 그 보안 등급을 적용하는게 되고 만약 특정 어셈블리를 로드할 때만 붙여 넣으면 해당 어셈블리에 대해서만 보안 등급을 적용하는 것이다.

뭐 구질 구질하게 설명하는 것보다 간단하게 코드로 살펴보자.

우선 특정 어셈블리에만 보안 등급을 설정하려면, 
object[] MyZone = { new Zone(SecurityZone.Internet)};
Evidence MyEvidence = new Evidence(MyZone, null);
AppDomain MyDomain = AppDomain.CreateDomain("MyDomain");
MyDomain.ExcuteAssembly("AnotherAssembly.exe", MyEvidence);

그리고 전체 Application Domain에 적용하고 싶다면,
object[] MyZone = { new Zone(SecurityZone.Internet)};
Evidence MyEvidence = new Evidence(MyZone, null);
AppDomain MyDomain = AppDomain.CreateDomain("MyDomain", MyEvidence);
MyDomain.ExcuteAssembly("AnotherAssembly.exe");

여기서 잘 보면 Evidence 객체를 생성할때 생성자에 두 개의 변수를 입력 받도록 되어 있고 두번째 녀석은 null로 되어 있는데 첫번째 인자는 host evidence이고 두 번째 인자는 assembly evidence이다. 첫번째 인자를 설정하면 두번째 녀석은 설정안해도 자동으로 첫번째 인자를 이용한다. 다만 프로그램에서 어셈블리 생성시 적용되는 보안 등급을 다르게 해야 한다면 두번째 인자도 설정해주면 된다. 뭐, 별로 그럴일은 없어 보이지만..



posted by 대갈장군
2010. 7. 9. 05:04 카테고리 없음
행복, 사랑, 진실. 이런 단어들은 원래부터 정의를 내리기 힘든 것들이다. 사람마다 기준이 다르기 때문이다.

돈이 아주 많고 누릴것 다 누리고 사는 사람이 스스로를 불행하다고 하며 무일푼의 거지가 행복하다는 것은 행복이라는 것이 얼마나 상대적인가를 보여주는 극단적인 예이다.

사람이 행복하다고 느끼는 순간은 일반적으로 자신이 원하는 것을 모두다 가졌거나 간절히 바라던 것을 이루었을 때이다. 하지만, 세상에는 가지려고 아무리 용을 써도 가지지 못하는 것이 존재하며 사람이 아무리 많이 가진다고 한들 세상의 모든 것을 가질 수는 없다. 게다가 죽으면 살아생전 가진 것들은 말짱 꽝이다.

행복해지기 위한 가장 빠르고 쉬운 방법은 '가지려는 마음'을 버리는 것이 아닐까 싶다. 동시에 '가지고 있는 것'에 대한 감사의 마음을 가지는 것. 이 두 가지가 동시에 작용하면 나는 이세상 누구도 부럽지 않은 행복한 사람이 된다.

사람이 행복할 수 없는 가장 큰 이유는 '비교' 때문이다. 나보다 더 가진 사람을 부러워하고 나보다 못 가진 사람을 깔보는 바로 그것이 사람을 불행하게 만들며 순간의 현실에 집착하게 만든다. 하지만 현실은 시간이 지나면 변하게 마련이다. 현실에 집착하게 되면 앞으로 걸어갈 수조차 없다.

사람이 행복할 수 없는 또 다른 이유는 '두려움' 때문이다. 원래 태어나면서부터 언젠가는 죽게되어 있는 사람은 미래에 대한 두려움은 떨쳐버릴수 없는 그림자처럼 늘 따라다니게 마련이다. 결국 벋어날 수 없는 것이라면 당연하게 받아들여야 한다.

나 역시도 죽음에 대한 두려움은 크다. 하지만 지금까지 살아온 날들에 더 감사하는 마음을 가지기 위해 노력한다. 인생이라는 것 자체를 즐겨보지 못하고 일찍 죽는 사람도 얼마나 많은가?

결론적으로 행복해 지기 위해서는, 가지려는 욕심을 버리고 가진것에 감사하며 자신만의 기준을 가지고 인생을 즐기면 된다.

죽음의 문턱에서 스스로의 인생에 대해 후회없이 살았다라고 말할 수 있다면 그 사람은 행복하게 살아온 것이다.
posted by 대갈장군
2010. 7. 2. 03:32 카테고리 없음

역시 한국은 스타크래프트의 나라인가 보다... 대한 항공이 스타 2로 도배한 747 기종을 도입할 예정이란다.


더 재미 있는 것은 기내식 메뉴인데... 


ㅎㅎㅎ 마지막에 gg를 부르는 눈보라 빙수! 메뉴 이름들이 센스 짱이다... 


posted by 대갈장군
2010. 7. 2. 03:25 카테고리 없음

인터넷 무료 저장 공간을 제공하는 웹사이트는 많지만 내가 요즘 들어 사용하게 된 Dropbox 라는 놈은 더더욱 편리한 것 같아서 좋다.

이 녀석을 설치하게 되면 2.5 GB의 저장 공간을 주는데 재미 있는 것은 단순한 저장 공간이 아니라 '동기화'를 알아서 해주는 저장 공간이다.

즉, 내가 여러대의 컴퓨터를 사용하더라도 지정된 폴더에 자료를 집어 넣기만 하면 설치된 Dropbox 프로그램이 알아서 들어온 자료를 인터넷 저장 공간에 업로드 하게 되고 다른 컴퓨터에서 Dropbox 프로그램을 설치만 하면 똑같은 폴더가 고대로 다른 컴퓨터에 나타나게 된다..

물론 FTP 같은 사이트는 어떤 면에서 더 간단하기는 하지만 Dropbox의 장점은 설치만 하면 바로 동기화가 자동으로 되므로 별도의 접속과정 없이 알아서 변경된 파일을 업데이트 하며 일반 폴더와 똑같은 형태와 모양으로 동작하기 때문에 사용자에게 매우 편리한 인터페이스를 제공한다.

실험삼아 몇장의 사진을 학교에서 올려놓고 집에서 접속해 봤더니 깔끔하게 동작한다. 집과 학교를 오가면서 조금 큰 파일을 복사해야 할 때에는 USB나 CD를 이용하곤 했는데 이 Dropbox를 이용하면 훨씬 더 쉽고 간편하게 자료를 사용할 수 있겠다....

초대장이 필요하신 분은 댓글 남기시면 초대장 쏘겠습니다. 물론 무료구~요~~
posted by 대갈장군
2010. 7. 1. 00:29 프로그래밍
아는 형한테서 받은 노트북이 너무 오래 되서 그런지 자꾸 CD를 못읽는 것이 문제의 시작이었다. XP 설치 시디를 어쩌다 인식하면 설치도중에 CD 내놓으라고 하면서 멈춰 버리기를 무한 반복하던중 구세주를 만났으니... 바로 다음 웹사이트 였다.http://www.boot-land.net/forums/index.php?showtopic=4900

여기 들어가면 USB_MultiBoot_10.zip 파일을 다운로드 받을 수 있다. 이 프로그램은 USB를 포멧하고 Windows XP나 기타 운영체제를 복사하도록 해주고 거기다 추가로 컴퓨터가 이 USB를 부팅시 제대로 인식할 수 있도록 각종 설정 파일을 설치하도록 도와 준다.

간단하게 말해서 윈도우 XP USB를 만들어준다. 다만 이것을 사용하기 위해서는 컴퓨터가 USB 부팅을 지원해야 한다. 다행히도 내가 받은 노트북은 BIOS 셋업에 보니 Harddisk 우선 순위에서 USB를 상위에 설정할 수 있게 되어 있었따.

우선 XP를 C 드라이브에 전체 복사 해 놓고 USB_MultiBoot_10.cmd 프로그램을 돌리면 cmd 창이 뜨면서 수동으로 각종 셋팅을 지정할 수 있는 창이 뜬다.


음, 마치 내가 해커가 된 기분... 캬캬캬

우선 0을 선택하고 엔터 때리면 USB-stick 옵션이 USB-Harddisk 옵션으로 바뀐다. 그리고 1번을 누르고 엔터 날리면 XP 복사본이 어디 있냐고 친절하게 물어온다. 간단하게 복사했던 XP 설치 시디 위치를 찾아주면 OK. 그리고 2번을 누르고 엔터 날려서 USB가 어느 드라이브에 꼳혀 있는지 알려준다.

그 외에 건드려야 할 것은 없다. 아, 그리고 위 과정에서 한번은 윈도우 설치에 대해 각종 정보를 입력하고 작은 윈도우가 뜨는데 걍 Unattended로 선택하고 필요한 정보, 뭐 사용자 이름, 시리얼 넘버 등등 같은거 설정해주면 된다. 걍 빈칸으로 넘어가도 상관없다.

다만 시리얼 넘버를 넣어주면 설치 중에 그것을 물어오지 않아서 편리하다.

그리고 나서 3번 누르고 엔터~ 그러면 마지막에 15분 걸리는데 XP 소스 파일 복사할래 말래 물어보는데 그냥 yes 날리면 뭐 잔뜩 복사한다. 끄읏! 그리고 USB 넣고 컴터 켜고 부팅한 다음 1번 선택하고 엔터.. 그러면 끄웃!
posted by 대갈장군
2010. 6. 25. 02:37 프로그래밍/C#
이벤트, 이벤트 핸들러. 이 두 단어는 API와 C++을 공부한 나에게는 아주 익숙하게 들린다. C#이 아닌 다른 언어에서는 이벤트란 API에서 비동기적으로 특정한 호출을 일으키는 명령을 의미하고 이벤트 헨들러는 그것을 받는 핸들러를 의미한다라고 아주 자연스럽게 이해가 된다.

하지만 C#에서 이벤트와 이벤트 핸들러는 좀 다른 의미다. 겹쳐지는 의미가 있기는 한데 바로 '비동기적 호출'이라는 점이다. C#에서 이벤트는 호출되어야 하는 함수의 목록을 의미한다. 중요한 것은 '목록'이라는 건데 이건 다수가 될 수 있다는 점이다. 즉, 멀티캐스트라는 것...

즉, 이벤트는 멀티캐스트 델리게이트로 구현되며 호출되어야 하는 함수 목록을 순차적으로 가진다... 그리고 이벤트에 의해 호출되는 함수를 '이벤트 핸들러'라고 한다. 이벤트를 핸들 하는 놈이라는 의미에서 이벤트 핸들러라 하는 갑다.

사실 C에 보면 메시지를 통해 이런 것을 구현했었다. 메시지를 특정 윈도우에 보내면 해당 윈도우의 메시지 처리 함수에서 메시지에 해당하는 함수를 구현하는 그런 방식이었다. 하지만 이것은 일단 복잡하고 비-객체 지향적이란다. 뭐, 객체 지향이네 아니네는 코딩을 어떻게 하느냐의 차이지만 C에서는 아무래도 언어 자체적인 객체 지향성이 C#에 비해 떨어진다는 의미다.

아무튼 이런 C의 메시지를 객체 지향적으로 포장한 것이 C#의 이벤트라는 것이다. 이벤트는 다음과 같이 선언한다.

엑세스지정자 event 델리게이트타입 이름;

이 위에 선언식을 보아하니 델리게이트와 좀 헷갈리지 않는가? 델리게이트의 선언은 다음과 같다.

엑세스지정자 delegate 리턴타입 이름(인수목록);

event를 선언하기 위해 사용된 델리게이트타입이라는 놈은 바로 델리게이트 타입 선언에 의해 선언된 놈이다. 즉, 예를 들면,

public delegate void MyDelegate(int a, int b);
public event MyDelegate
PrintOutEverything
MyEvent;

위와 같이 사용된다는 것... 델리게이트와 델리게이트 타입. 이 두 놈이 조금 복잡한듯 하나 위에 놈은 델리게이트의 타입 선언문이고 아래는 선언된 델리게이트 타입을 사용한다는 차이만 알면 될듯.

또 한가지 중요한 것은 이벤트 핸들러 즉, 호출 되는 함수는 리턴값을 가지지 않는다는 것. 원래 이벤트라는 것이 알려주기 위함이지 얻어오기 위함이 아니기 때문이다. 더군다나 이벤트 핸들러는 비동기적으로 호출되므로 리턴한다고 해도 받아 줄 놈이 없어졌을 수도 있다. 

그런데 자세히 보면 이벤트라는 놈은 사실 델리게이트타입을 재정의 한 것일뿐 특별한 차이점이 델리게이트와 비교해서 없다. 즉, 이벤트라는 지시자가 없더라도 델리게이트만으로도 모든 기능을 구현할 수 있다는 말이다. 사실 나도 이 부분을 MSDN 책을 보면서 '왜 두번 거쳐서 복잡하게 처리할까?' 라고 생각했던 부분인데 김상형님의 책에서 시원하게 설명해 주고 있다. 

이벤트는 델리게이트와 다르게 인수 정보를 사용자에게 보여주지 않고 감추며 멀티스레드에 안전하다는 장점이 있다. 즉, 사용자에게 보다 쉽고 안전한 방식으로 델리게이트를 사용하도록 했다는 것. 지금 보기에는 이것이 더 복잡해 보일지 모르나 비쥬얼 스튜디오의 마법사를 이용하면 이 과정이 사용자에게는 모두 숨겨지고 단 한번의 더블클릭으로 이루어 진다. 

그렇다면 실제로 이벤트를 폼에 적용하는 예를 살펴보자.

C#의 프로젝트를 폼 형태로 생성하면 메인 클래스는 반드시 Form을 상속받게 되어 있다. 이 Form 클래스에는 Paint라는 이벤트가 멤버로 들어가 있는데 바로 다음과 같이 선언되어 있다.

public event PaintEventHandler Paint;

여기서 PaintEventHandler가 바로 델리게이트 타입이다. 이 델리게이트 타입의 선언을 따라가보면 다음과 같이 선언 되어 있다.

public delegate void PaintEventHandler(Object sender, PaintEventArgs e);

보시다시피 리턴값이 없는 델리게이트 선언문이다. 고로 사용자는 위의 인수를 가지는 함수를 생성하여 Paint 이벤트에 대입만 해주면 화면 그리기 명령을 손쉽게 수행할 수 있는 것이다. 

이 방법 외에 윈도우에 그림을 그리는 방법이 한가지 더 있는데 바로 OnPaint 가상 함수를 재정의 하는 것이다. 이 경우에는 Control (부모)에 정의 되어 있는 OnPaint() 함수를 오버라이드 하는 것이다. 이렇게 하면 이벤트 핸들러를 사용할 필요가 없지. 

그렇다면 이 둘의 차이는? 만약 이 둘다 정의해 놓고 호출해 보면 오버라이딩 된 함수가 먼저 호출된다. 즉, OnPaint() 가상함수가 우선순위가 높다는 것이다.

헌데 막상 비주얼 스튜디오에서 더블클릭해서 이벤트 추가를 해보면 오버라이딩을 하지 않고 이벤트 핸들러를 사용하는 것을 알수 있다. 그 이유는 상속을 안받아도 되기 때문. 가상 함수를 오버라이딩 시킬려면 해당 함수를 가진 부모를 상속받아야 하는 불편함이 있다. 그에 비해 이벤트 핸들러는 델리게이트를 이용하므로 타입과 인수목록만 맞으면 자식 부모 관계 없이 호출 가능하다는 장점이 있다. 고로 이벤트 핸들러의 승리!

1. 이벤트의 정의는?
2. 이벤트 핸들러는 리턴값을 가지지 않는데 왜 그럴까?
3. 델리게이트와 이벤트는 어떻게 다른가?
4. 왜 Visual Studio에서 마법사로 함수를 추가하면 가상함수 오버라이딩 대신 이벤트 핸들러를 사용하는가?


'프로그래밍 > C#' 카테고리의 다른 글

Asynchronous programming  (0) 2017.05.31
C# - 제너릭 (Generic) 에 대한 질문  (0) 2010.06.18
Covariance and Contravariance  (0) 2010.06.18
델리게이트 - Delegate  (0) 2010.06.17
posted by 대갈장군
2010. 6. 18. 10:04 프로그래밍/C#
1. 제네릭이나 템플릿을 사용하는 이유? 역효과는?


2. 제네릭 타입 구체화 (Generic Type Instantiation) 이란?


3. 제네릭의 타입을 호출시 정확히 알려줘야 할 경우는 어떤 경우인가?


4. 제약 조건 (where)에서 가장 유용하다고 생각되는 것은 base, 즉, base를 상속받은 클래스이어야 한다는 조건인데 왜 그럴까?


5. 제네릭은 C++의 템플릿과 유사한데 C++과 무엇이 다른가?


6. 일반 컬렉션 (ArrayList)를 사용하게되면 예상되는 문제점은 없는가?


7. 일반 컬렉션 대신 제네릭 컬렉션 (List<T>)를 사용하게되면 왜 더 안전한 코딩인가?


'프로그래밍 > C#' 카테고리의 다른 글

Asynchronous programming  (0) 2017.05.31
C# 이벤트 - 객체 지향적 메시지  (0) 2010.06.25
Covariance and Contravariance  (0) 2010.06.18
델리게이트 - Delegate  (0) 2010.06.17
posted by 대갈장군
2010. 6. 18. 00:43 프로그래밍/C#
델리게이트에 대해서 공부하다 보니 공변성 (Covariance)반공변성 (Contravariance) 에 대한 이야기가 나왔다.

공변성과 반공변성... 뭔 소리인가... 라고 생각한다면 당신은 정상인...

수학 쫌 했다는 분들은 알아들을 수도 있겠다만 나는 처음 이 두 단어를 접하고 언어의 한계성을 느꼈다...

아무튼, 공변성과 반공변성은 사실 같은 원리에 근거한 같은 법칙을 말한다. 여기서 같은 원리란, 부모는 자식을 받아들일수 있으나 자식은 부모를 받아들일수 없다는 원칙이다. 쓰다보니 이런 패륜적인 원리일 줄이야... 헐.

일반적으로 자식 클래스는 부모 클래스로 부터 상속을 받아 여러가지 함수 및 멤버 변수를 추가하게 된다. 자, 그렇다면 자식은 양적으로 부모 보다 더 '많이' 가지고 있다. 반면 부모 클래스는 여러 자식들에게 공통으로 나누어 주어야 하므로 '적게' 가지고 있다.

부모/자식 클래스라는 헷갈리는 말 대신, 많다/적다로 표현하면 훨씬 더 이해가 빠르게 될 것이다. 그렇다면 부모 클래스에 자식 클래스를 대입하면 어떻게 되나? 다른 말로 적은 것 (부모)에 많은 것 (자식)을 넣게되면 자식이 가진 몇몇 함수 및 변수는 잘려 나가겠지만 그래도 잘라내면 그만이므로 문제가 없다.

헌데 반대로 자식에 부모를 대입한다면, 즉, 많은 것 (자식)에게 적은 것 (부모)를 대입한다면 문제가 생기는데 왜냐면 부모는 자식이 가지고 있는 것들을 가지고 있지 않기 때문에 '비어있는 공간'이 생기게 되고 이는 호출 오류를 일으킨다. 왜? 없는 것을 호출하니까...

그래서 부모(적은 것)는 자식(많은 것)을 받아들이지만 그 반대는 성립하지 않는다는 것이다.

함수를 살펴보면 "리턴타입 함수이름(인수)" 이런 형태다. 여기서 리턴 타입과 인수가 바로 '대입'이 일어나는 두 곳이다. 자 여기서 바로 공변성과 반공변성이 등장한다... 

일단 리턴타입의 경우 공변성을 가지는데 다른말로 풀어 쓰자면 위에서 설명한 기본 원리인 '부모는 자식을 받지만 그 반대는 성립하지 않는다'는 원칙을 눈으로 볼때 그대로 따른다는 의미다. 

즉, 선언한 델리게이트의 리턴 타입이 부모 클래스라면 자식 클래스 및 부모 클래스 타입을 리턴 타입으로 가지는 모든 함수를 받아준다는 이야기다. 당연히 그 반대는 안되죠오..

이제 남은 것은 '인수'인데, 여기서 이른바 '
반공변성
반공변성'
이 나온다. 말은 참 어려운것 같지만 한번만 풀어서 생각하면 같은 원리다. 이 반공변성은 위에서 말한 리턴 타입의 경우와 정 반대로 동작한다는 의미에서 붙여진 이름이다.

이것은 언제 '인수'가 대입 되는가를 생각해 보면 이해가 된다. 리턴타입의 경우 델리게이트 객체에 함수를 대입할 때 바로 '대입'이 일어나지만 '인수'는 델리게이트 객체에 함수를 대입할 때가 아니라 그 후에 대입된 함수를 호출 할 때 '대입'이 일어난다. 

고로 리턴 타입과는 달리 인수는 비교해야 하는 시점이 호출할 때이므로 델리게이트 객체에 함수를 대입할 때의 인수가 호출 시점의 인수보다 '부모'이어야 한다. 이것이 코드에서 보았을 때는 공변성과 정반대로 보이게 되므로 이름을 반공변성이라고 붙였다만 사실 알고보면 똑같은 원리에 근거한 것이다.

정리하자면 다음과 같이 말할 수 있다.

리턴타입 델리게이트객체(인수) = 리턴타입 함수객체(
);

위의 공식을 보면 좌측 리턴 타입이 우측 리턴 타입보다 큰데 이것은 좌측 리턴 타입이 우측 리턴 타입을 받아준다는 의미고 마찬가지로 우측 인수가 좌측 인수보다 크므로 받아준다는 의미다. 

이런 공변성과 반공변성을 잘 알고 있으면 델리게이트의 활용에 큰 도움이 될듯..







'프로그래밍 > C#' 카테고리의 다른 글

Asynchronous programming  (0) 2017.05.31
C# 이벤트 - 객체 지향적 메시지  (0) 2010.06.25
C# - 제너릭 (Generic) 에 대한 질문  (0) 2010.06.18
델리게이트 - Delegate  (0) 2010.06.17
posted by 대갈장군
2010. 6. 17. 23:31 프로그래밍/C#
델리게이트는 C#에 등장하는 새로운 함수 포인터다. 델리게이트의 사전적 의미는 '대표자'라는 의미로 명사일때와 동사일때 발음이 차이가 있으며... 아차차, 주제가 이게 아니지. 이놈의 토플 공부 습관은 사라지지가 않는다. -_-

그렇다면 우선 델리게이트 선언 형식을 살펴보자. 간단하다.

액세스지정자 delegate 리턴타입 이름(인수목록);

이것은 C++에서 사용하는 함수 포인터의 선언 형식보다 훨씬 더 가독성이 좋은 편이다. 

일단, C++과 비교해서 C#의 함수 포인터인 델리게이트의 장점 및 차이점을 나열해 보자.

  • C++의 함수 포인터에 비해 타입 체크가 훨씬 더 엄격하므로 잘못된 대입을 미리 막는다.
  • Delegate는 함수 포인터와 다르게 '클래스 타입'이다. 
  • 인수 목록에 반드시 이름이 필요하다.

  • 사실 위 3가지 차이점 중에 2번이 가장 크고 중요한 차이라고 개인적으로 생각한다. delegate가 클래스 타입이라고 했는데 이는 즉, delegate가 클래스를 선언하는데 사용되는 일종의 명시자라는 말이다. 자, 클래스라면 생성자를 사용해서 객체화를 하여 사용해야 한다. 고로 delegate를 사용하기 위해서는 delegate 클래스 타입으로 임의의 객체의 선언 및 생성자를 이용한 객체화가 요구된다.

    추가로 delegate는 엄연히 독립 타입이므로 어디에나 선언 가능하며 클래스 내부에 선언되면 액세스 지정자 (public, private) 를 줄수가 있다. 만약 외부에 전역으로 선언되면 엑세스 지정자는 굳이 필요하지 않다.

    다음과 두 함수를 보면 인수목록이 같고 리턴 타입이 같으므로 delegate를 쓸수 있다.

    public static void MyFunction1(int input) { Console.WriteLine("MyFunction1" + input); }
    public static void MyFunction2(int input) { Console.WriteLine("MyFunction2" + input); }

    이 두 함수를 가리키기 위해 델리게이트 타입의 클래스를 전역으로 선언한다면 다음과 같이 선언 할 수 있다.

    delegate void MyDele(int a);

    그리고 이제 이 선언된 MyDele 클래스의 객체를 객체화 (생성자를 이용한 구현) 를 하기만 하면 포인터 처럼 바로 사용가능하다.

    MyDele mDele;
    mDele = new MyDele(MyFunction1); //또는 mDele = MyFunction1;
    mDele(50);
    mDele = new MyDele(MyFunction2); //또는 mDele = MyFunction2;
    mDele(100);

    다시 한번 강조하지만 delegate는 클래스 타입이므로 delegate를 사용하기 위해서는 우선 delegate 클래스 타입으로 특정한 리턴 타입과 인수 목록을 가지는 클래스(MyDele)를 생성하고 이 클래스의 객체(mDele)를 생성하여 생성자로 가리킬 함수(MyFunction1 또는 MyFunction2)를 대입하면 만들어진 객체가 바로 그 함수가 된다.

    일단 C++ 방법에 비해 복잡해 보이지만 훨씬 더 '
    세련된
    세련된' 방식이다. 참고로 new로 선언한 후 해제하지 않았는데 우리 뒤에는 항상 Garbage Collector 가 알아서 쓰레기를 수거해 가는 것을 잊지 말자. +.+

    함수 포인터나 델리게이트의 장점은 바로 같은 인수로 리턴 타입을 가지는 여러개의 함수를 돌아가면서 가리킬 수 있다는 것인데 이런 장점은 사실 확 와닿지가 않는다. 이것의 장점을 몸으로 느끼기 위해서는 프로그램이 조금 커야 하며 설계 부터 상속을 염두해두고 만들어야 하며 가상함수들이 즐비해야 비로서 '아~ 이래서 델리게이트가 무려 챕터 하나를 차지하는구나...' 하고 느낄것이다.

    마지막으로 C++의 함수 포인터와 다른 큰 차이점으로 델리게이트는 다른 클래스에 속한 메서드를 가리킬 수 있다는 점이다. C++의 함수 포인터의 경우 임의의 클래스에 선언되어 있을 경우 그 해당 클래스 내부에 있는 메서드 만을 가릴킬 수 있었는데 델리게이트는 그것을 극복했다. 

    이것도 사실 '화악~' 마음에 와 닿지는 않지만 C++의 함수 포인터보다는 훠~얼씬 더 좋다는 것 정도는 알겠다. 

    정리하자면 C++의 함수 포인터는 단순한 변수였다. 말그대로 주소를 저장하는 포인터 였으나 C#에서 등장한 델리게이트라는 놈은 함수 포인터보다 훨씬더 가독성이 좋으며 독립적인 클래스 타입으로써 객체를 생성하여 사용한다는 점이 큰 차이다... 암튼, 당연히 델리게이트가 함수 포인터 보다는 좋다는 이야기지...

    더 많은 이야기를 하고 싶지만 코드가 들어가면 이야기가 너무 길어질 것 같아서 오늘은 여기까지만... 다음엔 공변성과 반공변성에 대해서 토크를 해야 할 듯...



    '프로그래밍 > C#' 카테고리의 다른 글

    Asynchronous programming  (0) 2017.05.31
    C# 이벤트 - 객체 지향적 메시지  (0) 2010.06.25
    C# - 제너릭 (Generic) 에 대한 질문  (0) 2010.06.18
    Covariance and Contravariance  (0) 2010.06.18
    posted by 대갈장군
    2010. 5. 15. 04:20 OpenGL
    OpenGL에서 작게는 10만개에서 많게는 100만개 정도 까지의 점을 그려야 하는 일이 있었다. 각각의 점들은 UTM 좌표들인데 이 UTM은 타원인 지구를 2차원 평면을 평평하게 편 다음 각 구역을 나누어 기준점으로부터의 거리를 미터로 나타낸다.

    그래서 UTM은 좌표의 구성이 Easting, Northing, Altitude 요렇게 세가지 축으로 구성된다. 뭐, 걍 X,Y,Z라고 보면 된다. 

    이 UTM 좌표 값은 미터로 표시되기 때문에 그 값이 무지 크다. 내가 스캔한 영역의 점들은 기본적으로 Easting 값이 710,000 이상이었으니까 무지하게 큰 값이다.

    이론에 따라 이 UTM 좌표를 XYZ로 생각하고 각 점들을 그려내 보았는데 이상하게도 몇개의 점들이 서로 서로 모여서 Z 방향으로 라인을 만드는 것이었다.

    다른 형태로 출력한 같은 데이터를 QT modeler라는 프로그램을 이용해서 보면 훨씬 조밀조밀하게 나오는데 이상하게 OpenGL로 렌더링 한 점들은 모두가 띄엄띄엄 한 것이었다.

    아무리 옵션을 바꿔봐도 문제는 고쳐지지 않았고 데이터 스트럭쳐 확인 및 브레이크 포인트를 이용해 각각의 요소를 확인해 보았지만 어디에도 타입 변경에 따른 문제는 없었다.

    고민고민하다가 생각한 것이 너무 큰 정수부분을 없애자는 것이었다. 임의의 인접한 두점은 대략 0.001 정도의 간격을 가지는데 정수부분의 70만 인것을 감안하면 소수 부분은 턱없이 적은 차이라는 점이 맘에 걸렸었다.

    그래서 모든 점들을 다 읽어들인후 중간값을 찾아내 그 정수값을 모두 빼내었다. 그리고 나서 다시 똑같은 방법으로 렌더링을 했더니 이제서야 모든 점들이 제대로 분포하는 것이었다.

    그렇게 고치고 나서 생각해보니 한 3년전에 들었던 수치 분석 수업에서 제한된 표현크기를 가지는 컴퓨터의 타입들(예를 들자면 integer, double 같은 것)을 사용할때는 아주가까운 두값이 연산에서 수많은 에러가 발생가능하다는 교수님의 말이 스쳐 지나갔다.

    아직 왜 인지는 정확히 모르겠으나 분명히 큰 정수부분의 표현을 위해 제한된 비트를 소모해 버리느라 소수점 이하 영역의 차이를 제대로 계산해 내지 못한 것은 분명하다.

    아무튼 이번 경험은 소중한 헤딩이었다. ㅋㅋㅋ
    posted by 대갈장군