• 다중 파일 어셈블리

    • myAseembly.dll에 포함된 세 개 파일 모두 하나의 어셈블리에 속함

    • 하지만 파일 시스템에서는 이들 파일을 세 개의 개별 파일로 인식

    • Util.netmodule 파일은 아무러 어셈블리 정보를 포함하지 않기 때문에 모듈로 커파일

    • 어셈블리가 만들어질 때 MyAssembly.dll과 Util.dll및 Graphic.bmp와의 관계를 나타내도록 어셈블리 매니페스트가 MyAssembly.dll에 추가된다.

    • 코드 디자인시 단일 파일 어셈블리로 구성할 지, 다중 파일 어셈블리로 구성할 지, 다중 파일 어셈블리로 구성한다면 어떻게 구조화할 것인지를 결정해야함.

 

  • namespace와 assembly

    • namespace : data type들을 그룹화하는 논리적 개념

      • 하나의 네임스페이스는 여러 개의 어셈블리로 구성되어 질 수 있고,

      • 하나의 어셈블리는 여러 개의 네임스페이스로 구성되어질 수 있다.

  • 다중 파일 어셈블리 만들기

    • 다른 언어로 작성된 모듈을 결합하려는 이유로 사용

    • 자주 사용되지 않는 data type에 대해 필요할 때만 다운로드 되도록 모듈로 분리하고자 할 때 사용

    • Enterprise 환경에서 개발시 여러 개발자가 각각의 모듈로 생성하고, 이를 하나의 어셈블리로 통합

    • 생성 방법

      • 1단계 : 어셈블리를 구성하는 부속 파일에 대한 모듈 생성

      • 2단계 : 다른 모듈에 대한 참조를 사용하여 주 모듈 컴파일

        • /addmodule : 옵션을 사용하여 1단계에서 생성한 부속모듈에 대한 reference 추가

      • 3단계 : 어셈블리 링커를 사용하여 다중 파일 어셈블리 만들기

    • 1단계 : 어셈블리를 구성하는 부속파일에 대한 모듈 생성

 csc /t:module MyCode.cs // MyCode.netmodule 이라는 모듈 생성

 csd /out:util.netmodule /t:module MyCode.cs  // 모듈명 지정하여 생성

    • 2단계 : 부속 모듈에 대한 참조를 사용하여 주 모듈 컴파일

 csc /addmodule:util.netmodule /t:module Client.cs

 // Client.netmodule을 생성하면서 util.netmodule에 대한 reference 추가

      • 위 두 과정을 하나의 명령문으로 처리 가능

 csc /out:Client.exe Client.cs /out:util.netmodule MyCode.cs

 

    • 3단계 : 어셈블리 링커를 사용하여 다중 파일 어셈블리 만들기

      • al<moudle name> <module name>...

      • /out:<file name>

      • /main:<method name>

      • /target:<assembly file type>

 al Client.netmodule util.netmodule /main:MainClientApp.Main /out:MyAssembly.exe /target:exe

 

 

  • 어셈블리 링커

    • Assembly Linker는 모듈 또는 리소스 파일인 하나 이상의 파일에서 어셈블리 매니페스트가 있는 파일을 생성

      • /out : 필수옵션으로 AL이 만드는 파일의 이름을 지정

      • /embed : 모듈이 지정하는 리소스를 어셈블리 매니페스트가 포함된 이미지에 포함시킨다.

      • /link : 리소스 파일을 어셈블리에 링크

      • /main : 모듈을 실행 파일로 변환할 때, 실행 파일의 진입점에 해당하는 method

      • /target : 출력 파일의 파일 형식을 lib(코드 라이브러리), exe(콘솔 응용 프로그램) 또는 win(Windows 기반 응용 프로그램)으로 지정, default는 lib

 

[첨부 파일 : 소스 파일]

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 동영상 강좌

  • COM에 대하여

    • 이미 사용중인 검증된 코드의 재사용을 위해 COM 활용

    • 서로 다른 언어로 작성된 바이너리의 타입을 공유하기 위한 방법으로 COM 서버 생성

    • 버전관리의 문제

      • Client에서 COM 서버를 호출할 때 COM 서버의 버전을 확인할 방법이 제공되지 않는다.

      • 때문에 새로운 버전의 COM 서버를 설치하면 타입라이브러리를 새로 수정하고, 레지스트리를 업데이트하며, 상황에 따라 Client의 코드를 수정하는 상황도 발생(DLL 지옥)

    • 배포의 문제

      • COM 서버의 정보를 레지스트리에 등록하는 과정은 어렵지 않다.

      • 하지만 COM 서버의 위치나 이름이 바뀌게 되면, 레지스트리 변경이 쉽지 않게 된다. 이 경우 이 COM 서버를 접근하는 Client의 구성정보를 모두 변경해야 한다.

 

  • 어셈블리(Assembly) 특징

    • DLL 지옥의 탈출

      • 같은 COM DLL에 대한 서로 다른 버전을 동시 제공 가능

      • Client가 원하는 버전을 파악하여 해당 버전의 COM DLL을 정확히 로드

    • 레지스트리에 등록하지 않음

      • 어셈블리는 레지스트리 등록 대신 Assembly 내에 자신에 대한 메타데이터를 포함하게 된다.

      • 배포는 해당 파일을 원하는 위치에 복사하는 것으로 끝남.

    • COM 처럼 dll과 exe의 형태

    • 배포의 단위로써 코드 재사용 및 버전 관리를 가능하게 하는 단위

    • class 접근제한자인 internal의 허용 단위

 

  • Assembly Architecture

    • 하나의 assembly는 다중 모듈로 구성

      • 모듈(module)이란 유효한 파일의 이름으로 소스코드 파일이나 리소스(예 : 이미지 파일)

    • 일반적인 어셈블리는 네 가지 요소로 구성

    • 단일 파일 어셈블리

      • assembly metadata

      • type metadata

      • MSIL 파일

      • 리소스

    • 다중 파일 어셈블리

      • 자주 사용되지 않는 유틸리티 코드를 다른 모듈(별도의 소스파일)로 분리

      • size가 큰 리소스를 분리

      • .NET Framework에서는 파일이 참조될 때만 다운로드 하므로 이처럼 자주 참조되지 않는 코드와 리소스를 다중파일 어셈블리로 분리하여 구성하면 코드를 최적화 시키는 것이 가능

 

  • 어셈블리 매니페스트(Assembly Manifast)

    • Assembly의 핵심요소

      • 어셈블리 참조에 필요한 모든 정보를 내장

      • ID : 이름, 버전, 컬처, 공개 키

      • 파일목록 : 하나의 어셈블리는 하나 이상의 파일로 구성

      • 참조된 어셈블리 목록 : 외부에서 참조되는 어셈블리에 대한 정보

      • Permission 정보 : 이 어셈블리를 실행하기 위해 필요한 권한 정보

      • 형식 참조 정보 : reference와 그 reference의 선언/구현 사항이 포함된 파일을 매핑하는 정보

 

  • 매니페스트의 저장 방법

    • 단일 파일 어셈블리에서는 어셈블리를 구성하는 파일에 포함

    • 다중 파일 어셈블리에서는 별도의 독립실행형 매니페스트를 구성하거나 어셈블리를 구성하는 하나의 dll에 저장될 수 있다.

 

  • 단일 파일 어셈블리 만들기

    • 어셈블리 매니페스트, 형식 정보, 구현 코드 등의 하나의 파일로 구성된다.

    • 생성

csc MyCode.cs // MyCode.cs 모듈에 대한 어셈블리(MyCode.exe) 생성

 

    • 출력 파일명 지정

csc /out:MyAssembly.exe MyCode.cs

 

    • 라이브러리 생성

                    csc /out:MyCodeLibrary.dll /t:library MyCode.cs

 

 

  • 공유 어셈블리와 전용 어셈블리

    • 공유 어셈블리(shared assembly)

      • 재사용 가능한 코드에 대한 어셈블리의 생성(COM의 dll, exe처럼)

      • SN(Strong Name)을 가지고 있어야 한다.(sn.exe)

        • 버전 정보를 포함하고 있어야 한다.

      • GAC(Global Assembly Cache)에 등록해야 한다.(gacutil.exe)

    • 전용 어셈블리(private aseembly)

      • 응용 프로그램과 동일한 디렉토리 또는 서브 디렉토리에 존재

      • 버전관리나 클래스 이름 충돌의 문제가 없음

      • 특정 응용 프로그램에 종속적인 어셈블리를 구성할 때 사용

 

  • 어셈블리 정보 확인

    • Intermediate Language Disassembler Utility

    • ILDasm.exe

      • GUI를 통해 .NET assembly(EXE 혹은 DL)의 정보를 확인할 수 있다.

 

  • 버전 관리

    • 소스 코드 내에서 직접 입력 가능

    • [assembly:AssemblyVersion("1.0.1.0")]

      • 주버전.부버전.수정버전.빌드번호

      • 수정버전과 빌드번호는 *로 생략가능

    • [assembly:AssemblyVersion("1.0.*")]

    • 공유 어셈블리의 경우 버전이 다를 경우 함께 사용할 수 있다(서로 버전의 library를 함께 서비스 할 수 있다.)

 

[첨부 파일 : 소스 파일]

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 C# 동영상 강좌

  • 전처리기 지시문(Preprocess Directive)

    • Compile 시에만 처리되는 명령문

    • 특정 조건에서만 Compile 되도록 처리하기 위한

    • 여러 버전의 Apllication 생성을 위해

      • standard Edition

      • Enterprise Edition

    • 디버깅 정보를 제공하기 위해

      • Debug를 위한 버전(debugging을 위한 기능 추가)

      • Release를 위한 버전(Debugging을 위한 기능 제거)

    • #으로 시작되는 지시문을 제공

 

  • #define, #undef

    • Compiler에게 해당 기호의 정의 및 제거를 알림

 #define DEBUG            // DEBUG 기호의 정의

 #define ENTERPRISE   // ENTERPRISE 기호의 정의

 #define STANDARD     // STANDARD 기호의 정의

 #undif DEBUG             // DEBUG 기호의 제거

 #undif ENTERPRISE    // ENTERPRISE 기호의 제거

 #undif STANDARD       // STANDARD 기호의 제거

 

    • #if, #endif, #else, #elif 등과 함께 사용

    • attribute와 함께 사용 가능하다

 

  • #if, #endif, #else, #elif

    • 특정코드만 Compile되도록 조건을 명시

 #define ENTERPRISE

 

 #if (ENTERPRISE && STANDARD)

          Console.WriteLine("ENTERPRISE 버전입니다.");

 #elif (STANDARD)

          Console.WriteLine("STANDARD  버전입니다.");

 #else

          Console.WriteLine("TRIAL 버전입니다.");

 #endif

 

  • #warning, #error, #line

    • Compile 시 사용자 정의 메시지를 출력하기 위한 용도

 # if (ENTERPRISE && STANDARD)

          #error ENTERPRISE와 STANDARD가 같이 정의되었습니다.

          Console.WriteLine("ENTERPRISE 버전입니다.");

 #elif (STANDARD)

          #warning STANDARD 버전을 생성하고 있습니다.

          Console.WriteLine("STANDARD  버전입니다.");

 #else

          Console.WriteLine("TRIAL 버전입니다.");

 #endif

 

 #line 24 "여기는 24번 라인입니다." // 24번 라인이 compile 된다는 표시

 

  • #region, #endregion

    • 하나의 코드블럭을 형성하는 단위를 나타냄

    • Visual Studio.NET에서 코드블럭의 확장/축소가 가능함

 

 

[첨부 : 소스 파일]

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 C# 동영상 강좌

 

  • 객체의 생성과 소멸

    • 객체의 생성

      • new 연산자를 사용하여 class의 instance인 객체(object)를 생성

      • 이 때 객체가 생성되는 곳이 Managed Heap

    • 객체의 소멸

      • C++ 같은 경우 소멸자(destructor)를 정의하여 메모리 관리(리소스 해제)가 가능

      • C# 에서는 Garbage Collector가 메모리를 관리

        • 소멸자가 존재하지만 언제 호출되는지 예측할 수 없다.

        • 때문에 소멸자는 사용하지 않을 것을 권장

      • 불가피하게 객체의 소멸 작업을 해주어야 하는 경우

        • DB, 파일 및 네트워크 연결과 같은 것은 Unmanaged Resource 리소스 해제 시

        • IDisposable interfaceDispose() 사용

 

  • Garbage Collector

    • garbage

      • new 연산자를 통해 객체를 생성(managed heap)하여 사용하다가 해제된 메모리 공간

    • garbage collector

      • garbage collector는 managed heap이 부족하다고 판단되는 시점에 불필요한 객체의 Finalize()를 호출하여 객체를 소멸시키는 작업을 수행

    • 강제적인 garbage collector 작동

      • System namespace의 GC Class에 있는 Collect() method를 호출하여 garbage collector를 강제적으로 작동 시킬 수 있다.

      • 시스템에 성능 저하를 유발할 수 있어 불가피한 상황이 아니라면 강제 호출은 피해야 한다.

        • 예) 대용량의 객체를 사용한 뒤 시스템 부하를 줄여야 하는 상황

 

  • Gabarge Collection과 Generations

    • 생성된지 오래된 객체와 최근에 생성된 객체를 비교할 때 오래된 객체가 더 오랫동안 heap 영역에 남을 가능성이 높다.

      • Main()에 생성된 객체와 다른 method에서 생성된 객체를 비교

    • 0세대 : 최근에 생성된 객체, 단 한번도 garbage collection에 mark된 적이 없는 것

    • 1세대 : garbage collection이 mark했으나 아직 살아있는 객체, 즉 heap에 여유공간이 많아 제거하지 않은 객체

    • 2세대 : garbage collection이 mark한 후 , 한번 체크하고 갔지만 아직 살아있는 객체

    • garbage collection이 일어나면

      • 먼저 0세대에 해당하는 객체들을 mark하고 리소스 해제, 남은 객체는 다음 세대로 바꿈

      • 0세대 객체를 해제한 뒤에도 heap이 부족하면 1세대 객체도 mark후 해제

      • 그래도 부족하면 2세대도 mark 후 해제

 

  • System.GC class member

    • Collect()

      • GC가 heap에 있는 객체에 대해 FInalize()를 호출하게 함

      • 또한 특정 세대의 객체를 해제

    • GetGeneration()

      • 객체가 현재 속해있는 세대를 리턴

    • MaxGeneration

      • 시스템에 있는 2세대(최종 세대)를 리턴

    • ReRegisterForFinalize()

      • 현재 객체가 Finalize()를 호출하지 못하도록 되어 종료될 수 없을 때 종료 가능(finalizable) 상태로 재 등록

    • SupperessFinalize()

      • 현재 객체의 Finalize()를 호출하지 못하도록 설정

    • GetTotalMemory()

      • heap 영역의 사용중인 전체 memory를 리턴(byte 단위)

 

  • 소멸자(destructor)

    • new 연산자를 사용하여 객체를 생성하면 managed heap이라는 영역에 할당한다. 그 뒤

    • .NET Runtime은 자동적으로 Finalize() method를 지원하는가(소멸자가 구현되었는가)를 체크

    • 지원할 경우, 해당 객체의 reference를 finalization queue에 저장

    • GC가 garbage collection을 수행할 때 이 queue에 있는 객체들부터 처리하기 위해 소멸자를 호출

    • 때문에 소멸자만 믿고 기다리는 것은 좋은 방법이 아님

      • 더욱이 lock과 관련있는 작업이라면...

    • 소멸자는 Compile되면 Finalize()로 변환된다

    • Finalize()는 명시적으로 호출할 수 없기 때문에 소멸자를 사용해야 한다.

 class AnyClass{

          ~AnyClass(){

                          // 정리작업 수행

          }

}

 

 

 

 protected override void Finalize(){

            try{

                        // 정리작업 수행

            }

            finally{

                        base.Finalize();

            }

}

 

 

  • IDisposable interface와 Dispose()

    • GC는 관리되는 객체가 더 이상 사용되지 않을 경우 해당 객체에 할당된 리소스를 자동으로 해제하지만 garbage collection이 언제 발생할 지 예측할 수 없다

    • DIspose()는 코드내에서 리소스를 해제하도록 명시하는 방법

    • 객체가 더 이상 사용되지 않는 시점에 바로 리소스가 해제됨

    • Dispose()는 해당 객체의 GC.SuppressFinalize 메소드를 호출해야 한다

      • GC가 자동으로 호출하는 Finalize()는 리소스를 많이 소모하기 때문에 Dispose()를 통해 개체가 이미 정리된 경우라면 GC에서 개체의 Finalize 메소르드를 호출할 필요가 없다.

      • 현재 finalization queue에 있는 경우(소멸자가 구현된 경우) GC.SupperessFinalize()는 GC에 의해 Finalize 메소드가 호출되는 것을 억제

    • DIspose()를 구현할 때

      • class에 포함된 모든 리소스는 물론,

      • 상속 받았다면 base class의 Dispose()도 호출하여

      • 해당 base class의 모든 리소스도 해제해 주도록 한다.

 

[첨부 : 소스 파일]

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 C# 동영상 강좌



 
  • Exception(예외 처리)
    • Exception : Application이 실행중일 때 발생하는 오류를 처리하는 것
    • .NET에서 제공하는 구조화된 예외처리 방법
    • .NET에서 exception은 하나의 object
    • exception은 어떤 비정상적인 error 상황이 발생되었을 때, 그 문제에 대한 정보를 제공하는 객체
    • system이나 사용자가 정의한 모든 exception은 System.Exception에서 파생된 것


  • System.Exception class member property
    • HelpLink
      • 현재 예외와 관련된 도움말 파일에 대한 링크를 설정하거나 리턴
    • Message
      • 현재 발생한 Exception을 설명하는 text를 리턴
    • Source
      • Exception을 발생시킨 application이나 객체 이름을 설정하거나 리턴
    • StackTrace
      • Exception을 발생한 method의 stack 상세 정보를 리턴
    • TargetSite
      • Exception을 발생시킨 method name을 리턴
    • InnerException
      • 현재 예외를 발생시키는 Exception의 인스턴스를 리턴

 

  • try, catch, finnaly 개요
    • try : 프로그램이 수행되는 일반적인 코드
    • catch : exception 발생시 처리하는 코드
    • finally : 리소스를 해제하는 것과 같이 exception 발생 유무를 떠나 수행되어야 하는 코드

 

       

      try{

               // 일반 코드, exception 발생 가능성이 있는 코드

      }

       

      catch{

               // exception 발생시 처리되어야 하는 코드

      }

       

      finally{

               // exception 발생 유무와 상관 없이 수행되어야 하는 코드

      }

       

 

  • catch
    • 중첩된 exception 처리기를 지정할 수 있다.
    • 이때 지정된 순서대로 exception 처리기를 찾아 자신에 알맞는 처리기를 수행하고 더이상의 처리기를 찾지 않는다.
    • 때문에 catch를 다중으로 정의할 때, 상세한 것을 처리하는 처리기를 먼저 지정하고, 보다 일반적인 처리기는 뒤에 지정한다.
       

      catch(IndexOutofRangeException e){

                       // 배열 첨자가 넘어섰을 때 Exception 처리

      }

      catch(FormatException e){

                       // 형변환 오류시 Exception 처리

      }

      catch(Exception e){

                       // 일반 예외 처리

      }

      catch{

                       // C++ 등 Exception이 관리되지 않는 라이브러리에서 발생된 것 처리 

      }

 

 

  • 중첩된 try catch finally 구문
     

    try{

           // A : F, G 수행

           try{

                     // B -> 안쪽 Catch에서 exception 처리기를 찾아 실행, 안쪽에 처리기가 없다면 안쪽 finally를 수행하고,

                                 바깥쪽 catch에서 exception 처리기를 찾음. 이 때, E부분은 수행되지 않음.

           }

            catch(FormatException e){

                     // C -> 안쪽 finally를 수행하고, 바깥쪽 catch에서 exception 처리기를 찾음. 이 때, E 부분은 수행되지 않음.

           }

            finally{

                     // D -> 바깥쪽 catch 에서 exception 처리기를 찾음. 이 때, E 부분은 수행되지 않음

           }

            // E : F, G 수행

    }

    catch(Exception e){ // F 예외처리      }

    finally{ // G 정리작업                        }

 

 

  • custom exception
    • 별도의 class에 처리되기 원하는 예외 상황에 대한 상세하게 캡슐화하는 것
    • System.Exception class에서 파생
    • custom exception class내에 catch 블록에서 사용할 member field나 method를 정의하거나 overridding
    • 단순히 base class의 member를 호출하여 정의할 수도 있음

 

  • throw exception
    • 코드가 실행중일 때 일정한 조건을 충족하지 않는 경우에 throw 문을 통해 원하는 타입의 예외를 발생시킬 수 있다.
    • throw 키워드 뒤에 해당하는 exception의 instance를 생성하면 된다.

   throw new IndexOutOfRangeException("배열 첨자가 잘못되었습니다.");

 


출 처 : (주) 인터데브 솔루션 개발 사업부 박준호님 C# 동영상 강좌

박준호님의 C# 강좌 - 이벤트(Event)

프로그램&DB/C# 2009. 4. 14. 17:09 Posted by Josep.H.S
  • Event
    • 어떤 사건이 발생했을 때 Application에 통보하는 방법
      • 이벤트 발생기(publisher) : 이벤트 발생시 다른 객체에 이벤트 발생을 통보하는 일을 담당하는 객체
      • 이벤트 처리기(Subscriber) : 이벤트 발생시 실제 호출될 method(이벤트 핸들러)가 등록된 객체

 

  • Event 선언
    • Event와 함께 사용될 delegate의 정의 확인
      • delegate는 호출할 method의 형식만 정의한 것이기 때문에 해당 method의 형식이 이미 지정된 delegate가 있다면 그대로 사용이 가능하다

public delegate void AnyEventHandler(object sender, EventArgs e);

 

    • event 키워드를 사용하여 class에 event member 정의
      • public, protected, private, internal 등의 접근제한자와 static, new 등의 키워드

class MyClass{

         public event AnyEventHandler MyEvent;

}

  • Event 호출
    • class에 event를 선언하면 해당 event를 지정된 delegate 형식의 member field처럼 사용 가능
    • 이 class의 객체를 생성하는 클라이언트가 delegate를 event에 연결하지 않았으면 event는 Null이 된다.
    • delegate를 event에 연결하였다면 delegate를 참조하게 된다. 따라서 event 호출은 일반적으로 우선 Null인지 확인한 다음 event를 호출하여 실행

protected virtual void AnyMethod(EventArgs e){

        if(MyEvent != null)

                MyEvent(this, e);

}

    • event는 해당 event를 선언한 class에서만 호출 가능

 

  • Event 연결
    • event를 선언한 class 밖에서 event는 emmber field처럼 보이지만 할 수 있는 작업은 delegate를 추가하거나 제거하는 일만 가능하다
      • delegate 추가

anyobject.MyEvent += new AnyEventHandler(CalledMethod);

      • delegate 제거

anyobject.MyEvent -= new AnyEventHandler(CalledMethod);

 

  • Event와 Delegate
    • Event를 발생시키는 코드는 delegate instance를 호출하는 것과 동일
    • event member가 정의된 class를 사용하는 측에서 이 class의 instance가 발생하는 event를 받기 위해서는 delegate instance를 생성하고 event member에 delegate instance를 추가해야 한다.

 

  • Event guideline
    • Event Handler(이벤트 발생시 호출되는 method)는 .NET의 event guideline에 따라 아래의 두개의 parameter를 받는 메쏘드로 정의 된다.
      • object class type parameter sender
        • 동일한 Event Handler가 복수의 이벤트 발생기에 등록되어 질 수 있으므로 sender는 일반적으로 Event를 발생한 이벤트 발생기 객체에 대한 참조를 포함한다.
      • EventArgs class의 sub class type parameter e
        • 이벤트 발생기로부터 Event Handler로 전달할 부가적인 정보

void Onclick(object sender, EventArgs e){

          // 이벤트를 처리하는 코드

}

 

 

[파일 첨부 : 소스 파일]

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 C# 동영상 강좌


 

박준호님의 C# 강좌 - Delegate

프로그램&DB/C# 2009. 4. 14. 17:06 Posted by Josep.H.S
  • Delegate
    • 한 객체의 Method에서 자기를 생성한 객체의 함수를 호출해야 할 필요가 있을 때 사용
      • 한 시스템에 있는 객체가 다른 객체를 생성해서 그것을 사용하고, 또 그 생성된 객체가 자기를 생성한 객체의 함수를 호출하는 형태의 '양방향 호출'
      • Windows API의 Callback function(콜백 함수)를 생성하기 위한 function point 기능을 더 안정적으로 확장
    • event와 함께 사용되어 .NET Framework에서 event 처리에 많이 사용
    • 일반적인 method와 달리 compile 시에는 매개변수로 전달되는 method가 무엇인지   알지 못한다.


  • Delegate의 정의
    • 현재 정의 하는 delegate가 어떤 종류의 method를 나타내는지 compiler에게 알려주는 것을 의미
    • delegate를 정의할 때는 delegate가 나타내고자 하는 method의 signature의 완전한 사항을 명시해야 한다.
    • public, private, protected 접근자 사용 가능

                   delegate void OneOperation(uint x);

                   //하나의 uint parameter를 가지고 void를 반환하는 method의 delegate

                  

                   delegate double TwoOperation(long L1, long L2);

                   //두 개의 long을 parameter로 받아들이고 double을 반환하는 method의 delegate

 

                   public delegate string ThreeOperation();

                   // parameter가 없으며 string을 반환하는 method의 delegate

 

  • Delegate의 instance 생성 및 사용
    • new 연산자를 통해 delegate의 instance를 생성
    • 이 instance를 통해 method를 호출

       delegate void MyDelegate(string s); // delegate 정의

       public static void Hello(string s){ .....} // delegate가 호출할 method

       MyDelegate md = new MyDelegate(Hello); // delegate instance 생성

       md("Hello World~!") // delegate instance를 통해 Hello Method를 호출

 

       delegate int MyDelegate(string s); // delegate 정의

       public static int IntVal(string s){return 123;} // delegate가 호출할 method

       MyDelegate md  = new MyDelegate(IntVal); // delegate instance 생성

       int a = md("Hello World~!"); // delegate instance를 통해 Hello method를 호출

 

  • Multicast Delegate
    • delegate를 통해 두 개 이상의 method를 호출하는 것
    • 유의 : return 값에 있어서
      • Multicast delegate를 구현한다는 것은 한번의 호출로 두 개 이상의 method를 실행하는 것인데, 그 호출의 return 값이 여러개라면 어떤 값을 받을것인가?
      • 마지막 return 값 이외에는 리턴받을 수 없다.
    • Event 처리와 함께 주료 사용됨

delegate void MyDelegate(string s); // delegate 정의

public static void Hello(string s){.....} // delegate가 호출할 method 1

public static void Process(string s){....} // delegate가 호출할 method 2

MyDelegate md = new MyDelegate(Hello); // 첫번째 호출될 method 생성

md += new MyDelegate(Process); // 두번째 호출될 method 지정

md("Hello World~!"); // delegate instance를 통해 Hello Method를 호출

 

 

첨부 : 해당 강좌 소스파일

출 처 : (주) 인터데브 솔루션 개발 사업부 박준호님 C# 동영상 강좌




  • Collection
    •  배열의 경우 인덱스를 사용하여 각 항목(element)에 접근하게 되는데, Collection은 인덱스를 사용하지 않고 모든 element에 순차적으로 접근할 수 있는 방법을 제공한다.
    •  각 element에 순차적으로 접근할 수 있도록 허용하는 객체의 집합니다.
    •  객체가 열거자(enumerator)라고 불리는 객체의 참조를 제공하면 collection이라 한다.
    •  열거자는 Collection 내의 항목을 순차적으로 엑세스 할 수 있다.
    •  foreach를 통해 객체의 내에 순차적으로 접근 할 수 있도록 기능을 제공한다.

 

  •  Collection의 동작
    • Collection이 foreach와 함께 사용될 때 foreach는 collectionm의 Ienumrable interface로 부터 GetEnumerator() method를 호출
    • GetEnumerator()는 IEnumerator interface를 구현한 열거자 객체(enumerator object)를 return
    • foreach는 이 열거자 객체로부터 IEnumerator interface를 얻어 method(MoveNext(), Reset())와 property(Current)를 호출

 

  • Custom Collection
    • collection을 만드려면 System.Collections namespace의 IEnumrable interface를 구현해야 한다.

    interface IEnumrable{

IEnumerator GetEnumerator(); // 열거자 객체를 반환

    }

    •  열거자 객체는 System.Collections의 IEnumerator를 구현한다.

  interface IEnumrator{

object Curren{get;}

bool MoveNext();

void Reset();

  }

 

    •   IEnumerator를 구현한 Class의 객체는 다음과 같이 작동을 구현
      •    객체 초기화시 어떤 element도 가리키지 않음
      •    MoveNext method를 호출하여 첫번째 element로 이동한다.
      •    Current property를 통해 element를 뽑아낸다.
      •    MoveNExt를 호출하여 다음 element로 이동
      •    위 과정을 마지막까지 반복
      •    Current property가 null을 return하면 더이상 접근할 항목이 없다는 의미
      •    Reset method를 호출하여 처음으로 돌아가거나, 처리 종료
      •    Reset 호출시에는 첫번째 element의 이전을 가리키므로 MoveNext

 

  • ArrayList
    • 객체를 배열로 만들어 사용하는데 유용한 기능을 제공
    • 확장성이 뛰어나 삽입/삭제/열거 등의 기능을 제공할 수 있다.
    • 배열의 크기를 초기에 지정할 수 있다.
    • 정의된 크기를 초과하면 자동으로 크기를 늘려준다.
    •  ArrayList와 Collection의 관계
      • ArrayList는 IEnumerable interface를 상속받는다.
      • 때문에 ArrayList의 GetEnumerator를 통해 열거자 객체를 얻을 수 있다.
      • 이를 통해 순차적으로 ArrayList에 접근할 수 있다.
    • 생성 및 초기화
      •    ArrayList myAL = new ArrayList(); // ArrayList 생성
      •    myAL.add(new car("그랜저", 100000)); //초기화
      •    myAL.add(new car("체어맨", 200000));
      •    myAL.add(new car("포텐샤", 300000));
    • ArrayList 정보

   myAL.Count; // 실제로 저장된 element의 수

   int MaxSize = myAL.Capacity; //현재 ArrayList 총 크기 얻기

   myAL.Capacity = 20; // 저장될 수 있는 총 용량 설정(Default는 16)

    • element 제거

   myAL.RemoveAt(1); // 0부터 시작해서 지정된 요소를 제거

 

    • ArrayList를 배열로 변환
      • parameter로 배열을 전달해야 하는 경우 사용(Type 변환 주의)

   Car[] CarArray = new Car[myAl.Count]; // 저장할 배열 생성

   for(int i=0; i<myAL.count; i++){

           CarArray[i] = (Car)myAL[i];

   }

   foreach(Car i in CarArray){

           Console.WriteLine("차종 : {0}, 가격 : {1}", i.carName, i.carPrice);

   }

 

  • HashTable
    • 특정 Key 값에 의해 element에 접근할 수 있도록 고안된 데이터 구조
    • 어떠한 형태의 객체이든 저장 가능

  Hashtable hash1 = new Hashtable(); // HashTable 객체 선언

 

  hash1.Add("690810", "홍길동");

  hash1.Add("701116", "박길동");

  hash1.Add("740210", "김길동");

  hash1.Add("720929", "이길동");

 

  foreach(string item1 in hash1.Keys) {  // key data type에 의한 foreach 출력

           Console.WriteLine(item1 + "       " + hash1[item1]);

  }

 

[파일첨부 : 해당 소스 파일]

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 C# 동영상 강좌

박준호님의 C# 강좌 - Namespace

프로그램&DB/C# 2009. 4. 14. 16:59 Posted by Josep.H.S
  • Namespace

    • class와 각종 data type들을 그 연관성에 따라 그룹화시키는 논리적인 개념

    • Namespace를 중첩시켜 계층적인 data type을 구성

    • class의 이름 충돌을 해결하기 위한 용도로 사용

    • Namespace를 사용할 경우 이름이 길어지게 되는데, 이것을 해결하기 위해 Namespace Alias를 통해 Namespace의 별칭을 지정할 수 있다.

    • namespace에 포함될 수 있는 것

      • namespace, class, interface, struct, enum, delegate

 

  • Namespace의 범위

    • class는 그 class가 참조될 수 있는 범위를 가지고 있다.

    • namespace가 지정되지 않으면 같은 namespace에서 처리

 using System;

 class Utility{          // 이 두개의 class는 default namespace에 속한다.

          public void DisplayString(){  Console.WriteLine("Hello")};

 }

 

 class Myclass{

          public static void Main(){

                     Utility util = new Utility();

                     util.DisplayString();

 

                     System.Threading.Thread.Sleep(100000); // 다른 namespace class

          }

}

 

  • class 이름이 중복될 때

    • Application은 수많은 class들로 이루어지고, class의 이름이 중복되는 상황이 발생 할 수 있다.

    • namespace를 사용하지 않는다면, class의 이름을 서로 다르게 지정할 수 밖에 없다.

 public class Project1Utility{

             .............

 }

 

 public class Project2Utility{

             .............

 }

 

 // 복잡한 이름으로 사용이 불편

 namespace MyCompany.Project1{

             public class Utility{

             }

 }

 

namespace MyCompany.Project2{

             public class Utility{

             }

}

 

  • 단일 Namespace의 선언 및 사용

 namespace Project1{

             public class Utility{

                         public void DisplayString(string srt) {  ........ } ;

             }

}

 using Project1;

 namespace Project2{

             public class MyClass{

                          public static void Main(){

                                       Utility util1 = new Utility();  // using 키워드를 사용한 참조

                                       Project1.Utility util2 = new Project1.Utility();

                                       util1.DisplayString("Hello World~!");

                          }

             }

}

 

  • 중첩된 Namespace의 선언

 namespace MyCompany

                namespace Project1{

                             public class Utility{

                             }

                }

 }

                                                                               

 namespace MyCompony

                namespace Project2{

                             public class Utility{

                             }

                }

 }

 namespace MyCompany.Project1{

                 public class Utility{

                 }

 }

 

 namespace MyCompany.Project2{

                 public class Utility{

                 }

 }

 

 

 

 

 

 

  • Namespace의 사용과 Alias

 using MyCompany.Project1;

 

 // ....

 Utility util1  = new Utility(); // using 키워드를 사용한 참조

 MyCompany.Project1.Utility util2 = new MyCompony.Project1.Utility();

 System.Threading.Thread.Sleep(100000);

 using A1 = MyCompany.Project1; // namespace alias 정의

 

 // ....

 A1.Utility util2 = new A1.Utility(); // namespace alias 사용

 

 

[첨부 파일 : 소스 파일]

 

출처 : (주)인터데브 솔루션 개발 사업부 박준호님의 C# 동영상 강좌


3.3 구조체

3.3.1 구조체(structure) 소개

구조체를 사용하는 목적은 자료구조를 표현하기 위해서 있다. 기본적인 형태와 특징은 클래스와 비슷하다. 클래스와 마찬가지로 인터페이스에 대한 상속을 지원하며 메서드를 가질 수 있는 반면, 자료의 타입이 값 형태(Value Type)으로 지정된다. 이는 데이터에 대한 접근이 stack에 바로 접근해서 데이터를 가져올 수 있는 반면, 참조 형식(Reference Type)의 경우 stack에 접근해서 클래스의 Heap상의 위치에 대한 참조를 가져와야만 한다. 따라서, 간단한 자료 구조에 대한 표현이나 데이터형이 필요할 경우 구조체로 만드는 것이 성능면에서 유리하다는 것을 알 수 있다.

 구조체의 기본 형식은 다음과 같다.

/속성/

/엑세스 한정자/ struct [구조체 이름] [:interfaces]{}

 

* 구조체는 생성자, 상수, 필드, 메서드, 속성, 인덱서, 연산자, 이벤트 및 중첩 형식을 포함할 수 있다.

 

3.3.2 간단한 자료구조의 표현

한 점을 나타내는 포인터라는 구조체를 생각해보자.

 

 

 

3.3.3 속성

StructLayout LayoutKind열거자로 초기화되는데 LayoutKind의 멤버는 표와 같다.

멤버이름

             

Auto

런타임에 자동으로 레이아웃 선택. 관리되는 코드 외부에 노출시킬 수 없다.

Explict

관리되지 않는 메모리에 있는 각 멤버에 대한 정확한 위치 제어. 각 멤버는 FieldOffset 속성을 이용하여 나타낸다.

Sequential

관리되지 않는 메모리로 개체의 멤버를 보낼 때 Pack 속성에 따라 데이터 필드 맞춤을 지정 순서대로 배치한다.

 

 

3.3.4 Union 표현

  C C++를 배운적이 있다면 union이라는 키워드를 이용하여 만드는 공용체라는 것에 대해서 잘 알고 있을 것이다. Win32 API를 사용할 경우 매개변수 타입이 지정된 경우가 존재하는데, 이 경우 매개변수 타입을 만들어 낼 때 생기는 문제를 해결하기 위해 구조체의 StructLayout FieldOffset 속성(Attribute)를 이용하여 표현이 가능하다.

 

다음 예제는 구조체를 이용해 공용체를 흉내내 본 것이다.

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

28

30

31

32

33

34

35

36

using System;

using System.Collections.Generic;

using System.Text;

using System.Runtime.InteropServices;

 

namespace Union_Sample1

{

    class Program

    {

        static void Main(string[] args)

        {

            Union _union;   //구조체 선언

            _union.i = 0;   //구조체내 변수 i 초기화

            //byte변수들을 모두 1로 선언

            _union.b1 = _union.b2 = _union.b3 = _union.b4 = 1;

 

            Console.WriteLine(_union.i);

            System.Console.Read();

        }

    }

 

    [StructLayout(LayoutKind.Explicit)]

    public struct Union

    {

        [FieldOffset(0)]    //메모리내 시작 위치

        public int i;

        [FieldOffset(0)]    //0에서 시작

        public byte b1;

        [FieldOffset(1)]    //1에서 시작

        public byte b2;

        [FieldOffset(2)]    //2에서 시작

        public byte b3;

        [FieldOffset(3)]    //3에서 시작

        public byte b4;

    }

}

 

[결과]

16843009

 

 예제 소스를 실행해 보면 결과가 “1684309”와 같이 나온다는 것을 알 수 있다. 예제 소스에서 int 형 변수 i 4바이트 정수로 0으로 초기화 되었다. 그리고 변수 b1, b2, b3, b4를 모두 1로 초기화 하였다. b1, b2, b3, b4 4개의 바이트를 붙여서 나열해 비트(bit)형태로 표현해 보면 “00000001 00000001 00000001 00000001”과 같다는 것을 알 수 있다. 이를 10진수로 변환하면 “1684309”가 된다는 것을 알 수 있을 것이다. 결과적으로 int 형 변수 i의 값을 byte형 변수 4개가 공유하여 이용한다는 것을 이해할 수 있을 것이다