[ClouDeveloper News – Azure Edition] 2016년 12월 15일

클라우드 컴퓨팅을 중심으로 관련된 여러 기술과 업계 소식을 매주 전하는 ClouDeveloper News를 시작합니다. 파일럿 프로그램으로 구상하여 운영 중에 있으며 추후 여러 피드백과 의견 수렴을 통하여 프로그램의 틀을 갖추어 나갈 예정이오니 많은 관심과 구독을 부탁드립니다.

이번주 커뮤니티 소식

Azure 서비스 공지 사항

  • General availability: Package Management extension for Visual Studio Team Services
    • Visual Studio Team Service에서 NuGet Package와 NPM Package를 관리할 수 있는 익스텐션 서비스가 새로 출시되었습니다. Visual Studio Marketplace에서 청약할 수 있는 상품입니다.
  • General availability: Azure IoT Gateway SDK
    • 기존 하드웨어나 인프라를 교체하지 않고, 게이트웨이 장치를 개발하여 Azure IoT와 자연스럽게 연동될 수 있도록 만들 수 있습니다. 오픈 소스로 공개된 Azure IoT Gateway SDK를 사용하여 기존 장치가 Azure IoT Hub와 직접 통신할 수 있는 여건이 되지 않더라도 원격에서 장치를 제어하거나 상태를 보고하는 대행 게이트웨이 하드웨어를 더 쉽게 개발할 수 있습니다.
  • With general availability, enhancements abound in Azure IoT Hub Device Management
    • Azure IoT Hub에서 그동안 강조되지 않았거나 샘플 코드 수준으로만 제공되어오던 “장치 관리”에 관련된 기능과 API가 GA로 전환되었습니다. 예약 작업, 다이렉트 메서드, 쿼리, 디바이스 트윈 API를 사용하여 좀 더 많은 장치 제어 시나리오를 커버할 수 있게 되었습니다.
  • Latest update of Azure Analysis Services preview brings scale up and down
    • Azure Analysis Service의 인스턴스 크기를 조정할 수 있는 기능이 포털에서 새롭게 제공됩니다. 상황에 따라 강력한 성능 발휘를 위하여 인스턴스 등급이나 규모를 늘리고, 사용하지 않는 때에는 최소한으로 낮추어 경제적으로 Azure Analysis Service를 활용할 수 있게 됩니다.

교육 자료

새로운 제품 및 서비스

  • Introducing Windows Server & SQL Server Premium Assurance
    • 지원이 중단될 예정인 Windows Server와 SQL Server에 대한 보안 업데이트 제공 서비스가 유상으로 제공됨에 따라 기존 라이프사이클에서 최대 6년까지 지원이 연장됩니다. 신규 플랫폼과 서비스로 이행을 하기에 시간적 여유가 없는 경우 선택할 수 있는 옵션입니다. Windows Server 2008, Windows Server 2008 R2, SQL Server 2008, SQL Server 2008 R2가 첫 지원 대상입니다.
  • Announcing SQL Server Management Studio – 16.5.1 Release
    • SQL Server Management Studio의 최신 버전인 16.5.1이 릴리스되었습니다. 제품 출시 후 발견된 문제점들을 수정한 패치 성격의 업데이트 버전입니다.

활용 및 노하우

웹 캐스트

  • SQL Server + Java: What’s new
    • 새 Microsoft JDBC 드라이버를 통해 Java 기반 애플리케이션에서 SQL Server에 접속하여 쓸 수 있는 새로운 기능들을 소개하는 웹 캐스트입니다. 최근 JDBC 드라이버의 소스 코드를 GitHub 리포지터리에 게시하여 오픈소스화 하였으며, Maven 리포지터리를 통하여 JDBC 드라이버에 대한 종속성을 간편하게 추가할 수 있게 되었습니다.
  • Azure Media Indexer 2: Japanese support, punctuation improvements, no more time limit
    • 동영상에서 화자가 말하는 언어를 음성 인식하여 자막을 만들고 동영상 검색의 기본 데이터를 형성하는데 도움을 주는 Azure Media Indexer의 새 버전에서는 Microsoft Research의 연구 성과를 바탕으로 지속적으로 품질과 성능을 개선하고 있으며, 이번 릴리스에서는 일본어 음성 인식 지원, 10분 길이 제한 해제, 발음과 문법 품질 향상을 주안점으로 두고 있습니다.
  • Get Started with Azure Functions
    • Azure Function에 대한 튜토리얼 웹 캐스트입니다.
  • Digital marketing solutions on Azure
    • Orchard, Umbraco와 같은 유명 CMS 솔루션을 Azure 위에서 기술적인 지식 없이 손쉽게 구축하여 디지털 마케팅 전략에 활용할 수 있는 방안을 소개하는 웨비나 세션을 소개합니다.
  • Dev and test better in the cloud
    • Azure 및 클라우드 환경에서 개발과 테스트 전략을 더 효율적으로 수행할 수 있는 방법을 소개하는 무료 웹 캐스트입니다.

서드파티 소식

  • Kafka Connect for Azure IoT Hub
    • Azure IoT Hub에 연결하여 데이터를 Kafka로 보낼 수 있는 Connector의 오픈 소스 버전이 새롭게 공개되었습니다.

ClouDeveloper 페이스북 페이지에 댓글로 의견을 남겨주시면 뉴스 발행 및 각종 정보 전달에 반영하도록 하겠습니다. 고맙습니다.

의견 남기기: https://fb.com/cloudeveloper

Jetty를 사용하여 Windows Azure에서 JSP 사이트 구축하기

Windows Azure에서 Java 기반의 응용프로그램을 만들고 호스트할 수 있다는 이야기는 지속적으로 제시되어왔었습니다. 하지만, JSP 서블릿 페이지도 Windows Azure에서 호스트할 수 있을까요? Microsoft Architect로 활동 중인 David Chou가 작성한 블로그 포스트에 답이 있습니다. 오늘 제가 올리는 블로그 포스트는 다음 포스트에 대한 설명을 기초로 중요한 부분을 추출한 것임을 밝힙니다. (http://blogs.msdn.com/b/dachou/archive/2010/03/21/run-java-with-jetty-in-windows-azure.aspx)


Jetty (http://jetty.codehaus.org/) 프로젝트는 자바 기반의 오픈 소스 웹 서버로, HTTP 서버로서의 역할과 서블릿 컨테이너의 기능을 제공합니다. 정적, 동적 컨텐츠를 모두 지원하고, 독립적으로 실행할 수도 있고, 다른 프로세스에 부착되어 실행되는 기능 또한 제공됩니다. 이러한 특성을 바탕으로, Apache Project의 ActiveMQ, Cocoon, Hadoop, Maven Project, BEA Web Logic Event Server, Eucalyptus, FioranoMQ Java Messaging Server, Google AppEngine 및 안드로이드, Eclipse용 웹 툴킷 플러그인, 레드햇 J보스, Sonic MQ, 스프링 프레임워크, 사이베이스 EA서버, 짐브라 데스크톱 등 광범위하게 Jetty가 채택되고 있습니다.


Jetty 프로젝트는 아래와 같은 기능들을 제공합니다.



  • 비동기 HTTP 서버

  • 표준 지향의 서블릿 컨테이너

  • 웹 소켓 서버

  • 비동기 HTTP 클라이언트

  • OSGi, JNDI, JMX, JASPI, AJP 지원

응용프로그램 컨테이너의 관점에서 보면, Jetty는 전통적인 Java 기반의 Web Application Server들 (Tomcat과 같은)을 대치하는 배포 방법으로 사용될 수 있으며, 스프링 프레임워크 및 관련된 모든 파생 프로젝트들, EJB 컨테이너 등 대부분의 일반적인 웹 기반 자바 어플리케이션을 손쉽게 제공할 수 있는 것이 특징입니다.


Windows Azure에서의 Java 기술 지원


PDC’09 이후로 http://code.msdn.microsoft.com/winazuretomcat 웹 사이트를 통하여 Windows Azure 환경 위에서 Tomcat을 이용하여 JSP 기반 웹 응용프로그램의 구동 가능 여부와 샘플 코드를 지속적으로 홍보해왔었습니다. 그리고 이러한 사실을 바탕으로 http://blogs.msdn.com/jonbox/archive/2009/11/17/domino-s-demonstrates-tomcat-site-on-windows-azure.aspx 에서는 도미노 피자의 기존 피자 온라인 주문 웹 서비스를 Windows Azure 환경에서 구동하는 사례도 선보였습니다. 아래는 그동안 언급되거나 발표되어왔던 Windows Azure 환경에서의 Java 구동 방법에 관한 간략한 리스트입니다.


  • http://code.msdn.microsoft.com/winazuretomcat
  • http://www.interoperabilitybridges.com/projects/windows-azure-sdk-for-java.aspx
  • http://microsoftpdc.com/Sessions/SVC50
  • http://blogs.msdn.com/jonbox/archive/2009/11/17/domino-s-demonstrates-tomcat-site-on-windows-azure.aspx

  • 그러나 위에서 언급하는 Tomcat만이 Windows Azure 환경에서 사용할 수 있는 유일한 Web Application Server의 종류는 아닙니다. 사실, 위의 접근 방법들은 모두 Windows Azure Role에 함께 첨부되어 배포되는 Java 실행 환경 (JRE)를 기초로 하는 것이고, 그러므로 어떤 종류의 Java 패키지이든 관계없이 명령줄을 통하여 Classpath를 명시하는 방식으로 실행될 수 있습니다. 대개의 경우, 작업자 역할 (Worker Role) 패키지 위에서 실행되도록 디자인되고, Windows Azure 환경으로 배포될 수 있습니다. 그리고, 당연한 이야기이지만 Java와 Fast CGI를 결합하고, IIS 7.x를 기반으로 Fast CGI를 지원하는 Web Role을 이용할 수도 있습니다. 이 부분은 나중에 좀 더 자세히 소개하도록 하겠습니다.


    Windows Azure 환경에서 Jetty 실행


    아래는 실제 Windows Azure 환경에서 Jetty를 기반으로 실행하는 Windows Azure Worker Role의 구동 예시입니다.



    위와 같이 구현하기 위한 방법을 지금부터 차례대로 따라해보기로 하겠습니다.


    1. Windows Azure Worker Role 프로젝트를 만들고, Worker Role 진입점 메서드인 Run 메서드의 중심부에 다음과 같이 프로그래밍합니다.


    string response = “”;
    try
    {
        System.IO.StreamReader sr;
        string port = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints[“HttpIn”].IPEndpoint.Port.ToString();
        string roleRoot = Environment.GetEnvironmentVariable(“RoleRoot”);
        string jettyHome = roleRoot + @”approotappjetty7″;
        string jreHome = roleRoot + @”approotappjre6″;
        Process proc = new Process();
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.StartInfo.FileName = String.Format(“”{0}binjava.exe””, jreHome);
        proc.StartInfo.Arguments = String.Format(“-Djetty.port={0} -Djetty.home=”{1}” -jar “{1}start.jar””, port, jettyHome);
        proc.EnableRaisingEvents = false;
        proc.Start();
        sr = proc.StandardOutput;
        response = sr.ReadToEnd();
    }
    catch (Exception ex)
    {
        response = ex.Message;
        Trace.TraceError(response);
    }


    제가 이전에 게시한 글 “[Software Development/Windows Azure] – Windows Azure 들여다보기“에서 언급한 내용들을 참조하여 위의 코드를 보시면 이해하기 쉽습니다. 몇 가지 Windows Azure 환경에서 기본으로 제공되는 환경 변수, 디렉터리 설정 등을 바탕으로 Jetty 프로세스를 Java VM (java.exe)를 통하여 실행하도록 명령어를 구성하고 실행한 다음, 표준 출력의 내용을 Windows Azure Worker Role Process로 가져오도록 만드는 것을 볼 수 있습니다.


    2. Jetty 프로젝트와 Java VM의 최신 버전을 Windows Azure Worker Role 프로젝트에 추가합니다.


    다음 그림과 같이 폴더를 구성하면 되겠습니다. jetty7 폴더와 jre6 폴더 아래에 직접 해당 프레임워크 및 시스템의 실제 디렉터리 구조가 오도록 맞추면 문제 없습니다. 참고로, 확실하게 동작할 수 있도록 만들기 위하여 Java VM의 경우는 특별히 Windows Platform을 기반으로하는 x64 아키텍처 버전을 다운로드하여 아래 그림과 같이 넣어두어야 합니다. (중요)



    3. ServiceDefinition.csdef 파일 수정하기


    1단계에서 사용한 HttpIn이라는 설정을 Worker Role에 추가해야 하므로, ServiceDefinition.csdef 파일을 찾아 “WorkerRole” 요소 아래에 다음과 같이 내용을 추가하고 저장합니다. 참고로 이 설정은 Windows Azure Worker Role이 80번 TCP 포트 통신이 필요함을 Windows Azure 환경 내의 방화벽에게 통지하기 위한 목적으로 사용됩니다.

    <Endpoints>
      <InputEndpoint name=”HttpIn” port=”80″ protocol=”tcp” />
    </Endpoints>

    4. Windows Azure에서 사용할 수 있도록 Jetty 환경 설정


    Jetty가 사용되거나 환경 설정을 만드는 방법은 Windows Azure 환경에서 여러 가지가 있을 수 있지만, 특별히 이와 같이 Worker Role 위에서 Standalone Server로 동작하기 위하여 필요한 환경 설정이 있어서 이를 소개합니다. Windows Azure 환경에서는 Jetty가 기본으로 사용하는 NIO ChannelConnector 대신 BIO SocketConnector를 사용하도록 구성해야 합니다. NIO ChannelConnector에서는 내부적으로 루프백 연결을 기초로 하지만 Windows Azure 환경에서는 이것이 가로막혀있기 때문이라는 것이 David Chou의 설명입니다.


    이러한 설정을 수정하기 위해서는 Jetty 패키지 디렉터리 아래의 etc 디렉터리의 jetty.xml 파일을 수정해야 하며, <New> 태그의 class attribute를 org.eclipse.jetty.server.nio.SelectChannelConnector 대신 org.eclipse.jetty.server.bio.SocketConnector로 변경하고, NIO ChannelConnector에만 한정되는 몇 가지 옵션을 제거하는 방법으로 변경이 가능하며 정리하면 다음과 같습니다.


    <Call name=”addConnector”>
      <Arg>
        <New class=”org.eclipse.jetty.server.bio.SocketConnector”>
          <Set name=”host”><SystemProperty name=”jetty.host” /></Set>
          <Set name=”port”><SystemProperty name=”jetty.port” default=”8080″ /></Set>
          <Set name=”maxIdleTime”>300000</Set>
        </New>
      </Arg>
    </Call>


    그리고 좀 더 최적화된 설정을 위하여, Jetty가 자체 로그를 기록하지 않도록, etc 디렉터리의 jetty.xml 파일에서 RequestLog 핸들러 부분을 주석으로 처리하고, 확장자가 war인 패키지의 압축을 풀지 않도록 etc 디렉터리의 jetty.xml 파일에서 addBean “org.eclipse.jetty.deploy.WebAppDeployer”의 “extract” 프로퍼티의 값을 “false”로 지정하고, contexts 디렉터리의 test.xml 파일에서 <Set name=”extractWAR”> 부분의 프로퍼티 값을 “false”로 지정하였다는 것이 저자의 설명입니다.


    이러한 설정들이 모두 적용된 실제 샘플은 http://cid-b43074894ffe6264.skydrive.live.com/self.aspx/.Public/Projects/JettyCloudService.zip 에서 다운로드받아보실 수 있습니다. 🙂


    마무리


    Windows Azure Platform이 Microsoft의 기술이므로 철저히 .NET Framework 기반의 응용프로그램 개발만을 지원할 것이라는 편견은 종합적으로 “잘못된 것입니다.” Windows Server 2008 R2의 기술을 기반으로 하고 있기 때문에, 여러분의 응용프로그램이 Windows Server 2008 R2, 그리고 64비트 환경에서 성공적으로 수행될 수 있는 조건을 갖추고 있다면 Windows Azure Platform은 성공적으로 여러분들의 클라우드 컴퓨팅으로의 계획을 이끌어 줄 수 있을 것입니다.


    만약 좀 더 심층적인 예제나, Tomcat 기반의 Windows Azure 구동 사례를 보기 원하신다면, http://code.msdn.microsoft.com/winazuretomcat 를 방문하셔서 샘플 코드와 문서를 다운로드하시기를 권합니다.


    감사합니다. 🙂

    [Memo] Java의 >>> 연산자와

    Java로 작성된 코드를 C#으로 옮길 필요가 있어 살펴보던 중 눈에 익숙하지 않은 Java 고유의 Bitwise Shift 연산자를 발견했습니다. Triple Shift Operator를 어떤 의미로 해석해야 가장 정확할지 확실히 알 수 없어서 인터넷을 검색하던 중 저와 같은 고민을 하는 개발자의 질문이 역시 stackoverflow.com에 있었고 명쾌한 해답을 얻을 수 있었습니다. 🙂


     질문: What is the equivalent (in C#) of Java’s >>> operator? Just to clarify, I’m not referring to the >> and << operators.

    답변: In C#, you can use unsigned integer types, and then the << and >> do what you expect. The MSDN documentation on shift operators gives you the details. Since Java doesn’t support unsigned integers (apart from char), this additional operator became necessary.

    위의 질문과 답변 내용에 입각하여 코드를 작성한다면 아래와 같습니다.


    /* Java Code /
    int x = 3;
    int y = x >>> 3;


    / Equivalent C# Code */
    int x = 3;
    int y = (int)((uint)x >> 3);


    Java에는 C#과는 달리 Unsigned Integer Type이 따로 정의된 것이 없기 때문에 이와 같은 특수한 연산자를 하나 더 정의하게 된 것이라는 설명도 스레드 하단부에서 찾을 수 있었습니다.


    자료 출처: http://stackoverflow.com/questions/1880172/equivalent-of-java-triple-shift-operators-and-in-c

    Java 기반의 Nintendo 64 에뮬레이터 – Jario64

    인터넷을 검색하다가 우연히 흥미로운 프로젝트 하나를 발견하게 되었습니다. .NET Framework나 Java 기반으로는 빠른 속도를 필요로 하는 게임 등을 개발하기가 대개 “적당하지 않다”는 선입견을 깨뜨리고 Nintendo 64 에뮬레이터를 만든 그런 프로젝트입니다. 바로 Jario64에 대한 내용이었습니다.


    Jario64는 Project64의 코드를 토대로 만든 GPL 라이선스를 따르는 오픈 소스 에뮬레이터 프로젝트로, 에뮬레이터를 통하여 구동할 수 있는 일반적인 게임 타이틀의 상당수를 지원한다고 소개되어있습니다. 다음은 Jario64로 구동되는 몇몇 게임 타이틀들의 실행 화면입니다.


    마리오 카트

    마리오 카트

    마리오 파티 2

    마리오 파티 2

    수퍼 마리오 64

    수퍼 마리오 64

    수퍼 스매시 브라더스

    수퍼 스매시 브라더스

    젤다의 전설

    젤다의 전설


    스크린 샷을 통하여 살펴보기로도 상당한 수준임을 짐작할 수 있습니다. 게임 소프트웨어를 반드시 C, C++이나 어셈블리어로 개발하지 않으면 안될거라는 선입견을 깨뜨리는 보기좋은 도전이었습니다. 그리고 아래 동영상은 유튜브에 게시된 실제 실행 모습을 비디오로 캡처한 것이니 같이 보시면 좋겠습니다. (사운드 플러그인은 아직 구현되지 않은듯 보입니다.)

    http://www.youtube-nocookie.com/v/bwEIEljOzOc&hl=ko&fs=1&border=1

    Java Runtime (http://www.java.com)을 설치하신 다음에 위의 WebStart 바로 가기 링크를 클릭하시면 실행해볼 수 있으니 가지고 계신 에뮬레이터 롬 파일이 있다면 재미삼아서 한번 돌려보시면 어떨까 싶습니다. 🙂

    루씬 라이브러리를 닷넷에서 사용하기

    웹 사이트에 한국어 검색 기능과 함께 한국어 인덱싱 기능을 추가하기 위하여 여러가지 라이브러리를 찾아보던 중, 자바 기반으로 작성된 한국어 형태소 분석기 라이브러리를 발견하였습니다. (http://cafe.naver.com/korlucene) Apache Lucene 위에서 실행될 수 있도록 만든 라이브러리였고 저는 이 라이브러리의 코드 중 일부를 발췌하여 J#으로 포팅하려는 계획을 세웠습니다.


    그러나, 현재 배포되는 J# 2.0 Second Edition까지도 Generic을 선언하지 못한다는(!) 중대한 결점을 알게 되었고, 같은 기능을 하는 C# 코드를 작성하기 위하여 시도해보았지만 Java의 Iterator와 .NET의 IEnumerator 인터페이스의 미묘한 의미차이 때문에 포팅 중에 많은 시간을 들이게 되어 결국 더 진척시키지 못했습니다.


    그리고 마지막으로 택한 방법인 IKVM을 이용한 컨버젼에서 매우 만족스러운 결과를 얻게 되어 글을 올려봅니다. IKVM은 현재 JDK 1.6 버전에 대응되는, .NET Framework 위에서 구동되는 자체 Java Virtual Machine과 함께, Java Compiler에 의하여 만들어진 Java Byte Code를 MSIL로 변환하는 기술, 그리고 JDK 1.6 라이브러리에 대응되는 OpenJDK로 구성된 소프트웨어 개발 도구입니다. Apache Lucene 라이브러리 전체와 한국어 형태소 분석 라이브러리를 포함하여 모두 IKVM을 통하여 가져오는 데에 성공하였습니다.


    제가 작업한 절차는 다음과 같습니다.



    • http://www.ikvm.net/index.html 에서 IKVM.NET 런타임을 다운로드 받습니다. x86 버전과 x64 버전이 모두 제공되며, 이 글을 작성하는 현 시점에서 0.40 버전이 릴리즈되었습니다.

    • http://www.apache.org/dyn/closer.cgi/lucene/java/ 에서 Java 버전의 Lucene을 다운로드하여, 이 중에서 lucene-core-x.x.x.jar 파일을 가져왔습니다.

    • http://cafe.naver.com/korlucene 에서 한국어 형태소 분석기 JAR 파일을 다운로드하였습니다.

    • ikvmc 도구를 통하여 다음과 같이 명령어를 지정하여 대응되는 DLL 파일을 생성하였습니다.
      ikvmc -target:library [형태소 분석기 JAR 파일] [Lucene Core JAR 파일]

    • 위와 같이 명령을 지정하여 나타나는 결과 DLL 파일을 다음의 DLL들과 같이 프로젝트에 참조 추가합니다. – 또는 – IKVM 관련 DLL을 모두 GAC에 등록해도 됩니다.


      • IKVM.OpenJDK.Core.dll

      • IKVM.OpenJDK.Misc.dll

      • IKVM.OpenJDK.Security.dll

      • IKVM.OpenJDK.SwingAWT.dll

      • IVKM.OpenJDK.Text.dll

      • IKVM.OpenJDK.Util.dll

      • IKVM.OpenJDK.XML.dll

      • IKVM.Runtime.dll

    • org.apache.lucene.analysis.kr 네임스페이스의 클래스들을 활용하여 작업을 실행할 수 있었습니다.

    여기서 주목할만한 부분은, ikvmc가 단순히 대응되는 코드만을 작성하는 것이 아니라, JAR 파일 내부에 포함된 리소스 파일에 대한 정보도 닷넷 프레임워크 리소스로 변환하여 저장하고 여기에 대응되는 코드도 자동으로 맞추어주기 때문에 IKVM을 위하여 자바 프로그램을 다시 수정하는 작업은 필요하지 않습니다.



    위와 같은 방법을 통하여 기존에 작성한 Java Code들을 손쉽게 .NET Framework 안으로 통합할 수 있습니다. 그리고 ikvmstub을 이용하면 Java Code에서 .NET Framework의 핵심 라이브러리들을 자유롭게 활용할 수도 있습니다.

    C# 2.0의 구문 살펴보기 Part 3: Generic 클래스

    C# 2.0은 지금 소개하는 Generic이라는 기술을 통하여 Object 형식을 다루는 방법을 새롭게 제공합니다. 더 이상 복잡한 조건문을 메서드 안에 배열할 필요가 없으며 이 개념을 통하여 새로운 디자인 패턴을 만들 수 있게 되었습니다. 이 글을 작성하는 현 시점에서는 아직까지 Generic의 정확한 번역 용어가 채택되지 않았으므로 원래의 뜻을 유지하기 위하여 Generic으로 표기하고 있으므로 양해 바랍니다.

    1. Generic 클래스의 문법 구조
    Generic 클래스를 선언하는 방법은 기존의 클래스와 유사합니다. 하지만 기존의 클래스 선언에는 없는 몇 가지 추가 구문이 명시되어야만 합니다. C# 구문을 기준으로 설명하도록 하지요.

    Visual Studio 개발자 여러분들을 위한 안내: Visual Basic .NET, J#, Visual C++, JScript .NET 및 기타 언어를 사용중이신 프로그래머분들께서는 MSDN Library 베타를 참조하십시오. J#에서 이 Generic을 사용할 경우 기존의 Java, J++, J# 1.x 문법과 호환되지 않는다는 점을 꼭 염두에 두시기 바랍니다. Visual C++ 8.x 버전의 컴파일러에서 Managed Extensions for C++의 키워드가 새롭게 바뀌었습니다. 그에 따라, Managed Extensions for C++ 1.x 버전으로 작성된 소스 코드에 대한 업데이트 또는 유지 보수가 필요할 것으로 예상됩니다. 그리고 이번 업데이트를 기준으로 하여 C++의 Template과도 일정 부분은 연동이 가능할 것으로 예상됩니다. (일부 형식 제한 지정과 같은 문법은 표준에 어긋나므로 주의하십시오.)


    [public | private | internal | …] [sealed | abstract] class [Class Name]
          <[Argument Type I], [Argument Type II], …, [ArgumentType n]> : [Parent Class], [Interface I], …
    {
      // Class Body
    }

    클래스의 이름과 상속 관계를 지정하는 영역 사이에 부등식 기호 ‘<‘, ‘>’ 안에 사용자 정의 형식을 지정합니다. 이 사용자 정의 형식은 임의로 이름을 붙일 수 있으나 클래스 이름의 명명법을 그대로 따르므로 클래스 이름의 명명법에 어긋나는 형태의 이름은 사용할 수 없습니다.

    Generic 인수에는 단순히 클래스 형식을 지정할 수도 있지만, 구조체 형식, 인터페이스 형식, 대리자 형식, 중첩 Generic 형식의 지정도 가능합니다. 다시 말해, 사용하기에 따라서는 이 Generic 인수 자체가 복잡한 인수 트리 구조를 생성할 수도 있다는 뜻입니다. 하지만 한 세대 이상 파고드는 예는 그리 많지 않으므로 어렵게 생각하실 필요는 없습니다.

    이 강좌를 처음 접하시는 프로그래머 분들 중에는 비교적 근래에 C++에서 도입된 개념인 Template을 떠올리신 분들도 계시리라 생각됩니다. 예상하신 그대로, Generic은 C++의 Template를 C#에 맞게 첨삭한 클론입니다. 하지만 Template에는 없거나 다소 불편한 개념을 수정한 것이 .NET 플랫폼의 Generic의 특징이라고 할 수 있습니다.

    2. Generic 클래스에서의 사용자 정의 형식 활용 방법
    Generic 클래스 안에서 사용자 정의 형식을 활용하시는 방법은 단순합니다. 사용자 정의 형식은 사실 System.Object 형식을 상속한 것과 다를 바가 없습니다. 그리고 Generic 클래스 인수 안에서 명시된 적이 있는 사용자 정의 형식은 중첩된 서브 클래스에서도 유효합니다.

    3. Generic 클래스의 인스턴스 만들기
    다음의 예제 코드를 살펴보도록 하지요.


    using System;

    namespace Test2
    {
      public class Generic1 <FirstType> : System.MarshalByRefObject
      {
           private FirstType m_firstType;

          public Generic1(FirstType firstType)
           {
               this.m_firstType = firstType;
           }

          public FirstType FirstTypeInstance
           {
               get
               {
                   return this.m_firstType;
               }
           }

          public override int GetHashCode()
           {
               return this.m_firstType.GetHashCode();
           }

          public override string ToString()
           {
               return this.m_firstType.ToString();
           }
      }

      public sealed class MainObject
      {
           [MTAThread()]
           public static void Main(string[] arguments)
           {
               Generic1<string> s = new Generic1<string> (“Test”);
               Console.WriteLine(“{0}”, s);
               Console.ReadLine();
           }
      }
    }

    Generic이 지정된 클래스는 형식 선언을 할 때 부터 인수를 지정되는 모습을 볼 수 있습니다. Generic1<string> 이라는 형식의 의미는 string (System.String) 형식만을 받아들이는 Generic1 클래스의 단편을 뜻합니다. 그리고 Generic1<string> 이라는 선언 자체는 하나의 형식 키워드가 되기 때문에 생성자를 호출할 때에도 다시 한번 Generic1<string> 이라는 이름을 사용하게 됩니다.

    4. Generic 클래스의 상속
    Generic 클래스의 상속에 관하여 새롭게 소개되는 용어가 하나 있습니다. 의미는 우리가 익히 알고 있으나 용어 자체는 새로울 것입니다. 기존의 클래스를 C# 2.0에서는 Concrete 클래스라고 새롭게 명명하였는데, 상속 관계를 설명할 때에는 반드시 알아두셔야 하는 개념입니다.

    Generic 클래스의 특성을 유지하면서 상속을 할 수 있을 때에는 자식 클래스도 Generic 클래스로 인정됩니다. 하지만 Generic 클래스의 특성을 유지할 수 없는 상속을 하여 Generic 클래스의 특성을 소멸시킨 상속을 한 자식 클래스는 Concrete 클래스로 취급됩니다. 봉인된 Concrete 클래스가 아닐 경우 얼마든지 새로운 상속 관계를 형성할 수는 있지만 부모에 관한 모든 Generic 정보에 대한 접근 권한은 잃어버립니다.

    4.1. Generic 클래스의 인수를 줄이는 상속
    다음의 구문을 살펴보도록 합시다.


    public class Parent1 <A, B, C> { … }
    public class Child1 <A, B> : Parent1 <A, B, int> { … }

    어떻습니까? Child1 클래스에서는 A와 B 형식만을 받아들이도록 되어있지만 Parent1 클래스의 형식 인자 목록을 충족하도록 선언하였습니다. 이것이 Generic 클래스의 인수를 줄이는 상속의 한 예입니다. 여기서는 특정 위치에 있는 하나의 인수를 제거하였지만, 원하는 위치에 원하는 수 만큼의 인수를 제거할 수 있습니다.

    4.2. Generic 클래스의 인수를 늘이는 상속
    다음의 구문을 살펴보도록 합시다.


    public class Parent2 <A, B, C> { … }
    public class Child2 <A, B, C, D> : Parent2 <A, B, D> { /* 인수 C를 활용하는 코드 */ }

    4.1 섹션과 마찬가지로 Parent2의 인수 목록을 Child2가 모두 만족하는 상속을 하였습니다. 남아있는 C 형식에 관한 활용에만 집중하면 Child2 클래스의 작업은 끝이 나는 것입니다.

    4.3. Generic 클래스의 인수를 유지하는 상속
    다음의 구문을 살펴보도록 합시다.


    public class Parent3 <A, B, C> { … }
    public class Child3 <AChild, BChild, CChild> : Parent3 <AChild, BChild, CChild> { … }

    인수의 이름이 달라지더라도 이상이 없음을 보여주는 예제였습니다.

    4.4. Generic 클래스의 관계를 끊는 Concrete 클래스
    다음의 구문을 살펴보도록 합시다.


    public class Parent4 <A, B, C> { … }
    public class Child4 : Parent4 <short, int, long> { … }

    Child4는 클래스 자체에 대한 상속은 제공하고 있지만 Generic에 관한 특성을 완전히 소멸시킨 것입니다. Child4 클래스가 만약 봉인된 클래스라면 Generic에 관한 측면은 물론 클래스 자체에 대한 상속마저도 봉인한 고립된 클래스가 됩니다.

    4.5. Concrete 클래스로부터 새로운 Generic 관계를 생성하기
    다음의 구문을 살펴보도록 합시다.


    public class Parent5 <A, B, C> : System.MarshalByRefObject { … }

    System.MarshalByRefObject 클래스 자체는 봉인 클래스가 아니기 때문에 새로운 Generic 관계의 생성을 허용한 것이 되었습니다. 만약 System.MarshalByRefObject 클래스가 봉인 클래스였다면 위의 구문은 오류를 유발할 것입니다.

    오늘 강좌는 Generic 클래스에 대한 것들을 살펴보았습니다. 다음회 강좌에서는 Generic 인터페이스에 대해서 살펴보도록 하겠습니다. 미리 말씀드리는 부분이지만 Generic 인터페이스의 상속도 섹션 4의 내용을 그대로 적용하므로 이 부분에 관한 충분한 실습을 통하여 감각을 익혀두시기를 권장합니다.

    좋은 하루 되십시오. ^^