반응형
년도는 꽤 오래 됐지만, 2001년 1월에 마소지에 기고된 글입니다.. PDF로 되있는 것을 글로 올려봅니다. 참고가 되시길....

인터넷의 발전과 더불어 많은 개발자는 기존의 언어보다 강력하면서 동시에 생산성이 높은 새로운
언어가 등장하기를 기다려 왔다.
지난해 6월 MS 닷넷 플랫폼과 함께 소개된 C#이야말로 이러한 개발자들의 욕구를 충족시킬 만하다.  C#은 비주얼 베이직처럼 애플리케이션 작성과 유지보수가 쉽고, C나 C++처럼 높은 성능과 유연성을 제공하며, 새롭게 등장하는 웹 환경과 조화되고 기존 애플리케이션과도 쉽게 통합시켜주는 그런 언어이다.
인브레인 연구개발팀
dotNET@inbrein.com
닷넷이 선택한 언어, C#


C#은 엔터프라이즈 애플리케이션 개발과 유지보수를 더 쉽게 할 수 있도록 MS가 개발한 언어다. 객체지향 언어인 C#을 이용하면 하이 레벨 비즈니스 객체에서부터 시스템 레벨 애플리케이션까지 다양한 범위의 컴포넌트를 개발할 수 있다. 이러한 컴포넌트는 C#의 기본적인 구현만으로도 웹 서비스로 전환돼 어떤 운영체제의 어떤 언어에서도 인터넷을 통해 호출될 수 있다.
무엇보다도 C#의 강점은 비주얼 베이직의 높은 생산성과 C++의 강력함을 동시에 제공하는 C/C++에서 파생한 객체 지향 언어라는 것이다.

마치 C++의 복잡성과 모호함을 제거하고, 비주얼 베이직의 장점만을 C++에 추가한 것처럼 보인다. C#은 문장, 식, 연산자가 C++와 유사하지만 형 안정성, 버전 관리, 이벤트와 가비지 컬렉션 (Garbage Collection)과 같은 영역에서 상당한 진보를 보여준다. 이러한 C#은 common API(닷넷, COM, 자동화, C의 API 등)에 대한 접근을 지원한다. 특히 C#에서는 unsafe mode를 지원해 가비지 컬
렉터의 통제하에 있지 않은 메모리를 포인터를 통해 직접 조작할 수 있다.


왜 C#을 사용해야 하는가?
개발자들 중에는 기존의 비주얼 베이직이나 C++ 같은 언어로도 애플리케이션을 구축할 수 있는데, 굳이 C#을 알 필요가 있느냐고 묻는 사람도 있을 것이다.

답은 간단하다.

C#이 닷넷 플랫폼 환경에서 애플리케이션 구축을 위해 설계된 최상의 언어이기 때문이다.

구체적으로 말하자면 다음과 같은 이유에서다.
첫째, C#은 개발자들이 다양한 엔터프라이즈 수준의 애플리케이션을 쉽게 구축할 수 있게 하는 단순하고, 형 안정적인 객체 지향 언어다.

둘째, 다음 특징을 통해 C#은 견고한 시스템 레벨 컴포넌트를 구축할 수 있게 한다.
◆ 기존 코드와의 통합을 위한 완벽한 COM/FlatForm 지원
◆ 가비지 컬렉션과 형 안정성을 통한 견고성
◆ 코드 신뢰 메커니즘을 통해 제공되는 보안성
◆ 확장된 메타 데이터 개념에 대한 완벽한 지원
셋째, C#은 다른 언어간, 플랫폼간, 레거시 데이터와 상호 운용할 수 있다.
◆ 완벽한 라이브러리 기반 접근으로 COM+ 1.0과 닷넷 서비스를 통한 완벽한 상호 운용성 지원
◆ 웹 기반 컴포넌트 상호작용을 위한 XML 지원
◆ 관리와 배포의 용이성을 제공하는 버전 관리


C# 제대로 바라보기
이제 C#의 주요 특징을 C++와 비교해 구체적으로 살펴보자. 주목할 만한 특징으로 단순성, 현대성, 객체 지향성, 형 안정성, 버전 관리, 호환성, 유연성 등 일곱 가지를 대표적으로 들 수 있다.
C#은 C++와 달리 배우기가 매우 쉽다.

이것은 C#이 지향하는 최고의 목표가 단순성이라는 점에서도 쉽게 짐작할 수 있다.

대표적인 예로 C#에서는 포인터가 사라졌다.

이제 개발자는 더 이상 메모리를 직접 관리할 필요가 없다.

즉, C#에서 닷넷 런타임이 제공하는 가비지 컬렉터가 자동으로 메모리를 관리해 주기 때문에 개발자는 메모리 누출에 대한 염려나 직접 메모리를 관리해야 하는 부담으로부터 자유롭다.

그러나 개발자가 unsafe 모드를 선언해 메모리를 직접 액세스할 수 있는 방법도 제공하고 있다.

또한 C#은 boxing과 unboxing 개념을 도입해 기본형이건 클래스형이건 간에 모든 형을 객체로 볼 수 있게 해주는 단일한 형 체계를 지원한다.

다음은 묵시적인 boxing을 통해 integer형 변수를 object형으로 다루는 예제다.

// integer형 변수 boxing
using System;


class TestBoxing
{
    public static void Main()
    {
        int i = 123;
        object o = i;  // 묵시적인 boxing
        i = 456;  // i값을 변경
        Console.WriteLine(“The value-type value = {0}”, i);
        Console.WriteLine(“The object-type value = {0}”, o);
    }
}


결과:
The value-type value = 456
The object-type value = 123


C#은 현대적인 감각을 갖춘 언어다.

개발자들이 C++로 구현하려면 매우 복잡하고 까다로웠던 과정을 C#에서는 기본적인 특징만으로 해결할 수 있다. 특히 회계형이 추가된 것은 엔터프라이즈 프로그래밍 환경에서는 무척 반가운 일이다. 우리가 흔히 기본형이라고 부르는 단순형 외에도 개발자들이 원한다면 개발 애플리케이션에 맞는 고유한 사용자 정의 데이터형을 만들어 낼 수도 있다.
앞서 언급했듯 포인터가 사라지고, 자동으로 메모리를 관리한다는 점에서도 C#의 현대성은 잘 드러난다. 예외 처리 측면에서도 C#은 기존 언어와 비교할 때 많은 향상을 보여준다(<리스트 1>).

예외 처리가 다른 언어간에도 가능하며, 예외 처리 구문(try/catch/ finally)이 매우 단순해져 C++의 HRESULT로 골치를 썩지 않아도 된다.

사용자 삽입 이미지

마지막으로 웹 환경에서 가장 중요한 측면인 보안에서도 C#은 메타 데이터를 제공해 닷넷 프레임워크의 보안 모델을 지원한다.

객체 지향성

C#은 객체 지향적인 언어로, 캡슐화(encapsulation)와 상속(inheritance), 다형성(polymorhism) 같은 객체 지향의 핵심적 개념을 지원한다.

구체적으로 C#은 전역 함수나 전역 변수를 지원하지 않는다.

대신 모든 것이 클래스 내의 인스턴스 멤버(클래스의 인스턴스를 통해 접근할 수 있다)나 static 멤버(형을 통해 접근할 수 있다)로 캡슐화된다.

이는 C# 코드의 가독성을 높이고 잠재적인 명칭 부여 갈등을 감소시킨다.

클래스 내의 메쏘드는 기본적으로 그 클래스의 파생 클래스가 오버라이딩할 수 없는 비가상(non-virtual) 메쏘드다.

이는 메쏘드를 우연히 오버라이딩해 또 다른 에러를 낳을 가능성을 제거한다.

만약 메쏘드를 오버라이드하기 위해서는 virtual이라는 제한자를 명시적으로 붙여야만 한다.

또한 C++와 마찬가지로 접근 제한자(access modifiers)를 통해 클래스 멤버마다 다른 접근 수준을 설정할 수 있다.

C#은 public, private, protected, internal 접근 제한자 를 지원한다.

또한 C#은 다중 상속에서 야기될 수 있는 많은 문제점을 고려해 단일 상속만을 지원한다.

즉, C# 클래스는 오직 단 하나의 기초 클래스만 가질 수 있다.

다중 상속이 필요할 때는 인터페이스를 구현하도록 한다.

형 안정성

C#은 형 안정성을 구현한다.

예를 들어 C#에서는 초기화하지 않은 변수를 사용할 수 없다.

한 객체의 멤버 변수는 컴파일러가 0으로 자동 초기화한다.

지역 변수일 경우에는 개발자가 직접 초기화 작업을 해야 한다.

그러나 실수로 초기화하지 않은 변수 를 사용하면 컴파일러가 경고를 내보내서 변수를 초기화하도록 한다.
이외에도 C#에서는 안전하지 않은 형 변환(casts)을 할 수 없다. 가령 integer형에서 레퍼런스형(예를 들어, object)으로 형 변환을 할 수 없다.
또한 배열 범위를 체크해 형 안정성을 구현한다.

배열이 실제 n-1개의 요소를 갖고 있을 때에는 그 이상의 배열 요소를 사용할 수 없다.

수리 연산의 결과가 지정된 데이터형의 범위를 벗어날 경우를 대비해 오버플로우 체크 기능을 설정할 수 있다.

C#은 애플리케이션 수준과 구문 수준 모두 오버플로우를 체크할 수 있으며, 반대로 오버플로우 체크 기능을 해제할 수도 있다.

버젼 관리

소프트웨어 컴포넌트를 업데이트하면 에러가 자주 발생하고 의도하지 않은 기존 프로그램의 의미를 변경할 수 있다.

이로 인해 버전관리의 문제가 발생하는데, 이를 해결하기 위해 C#은 적절한버전 관리 방법을 지원한다.

예를 들어, C#에서는 메쏘드 오버라이딩이 C++나 자바에서처럼 우연히 일어나지 않도록 반드시 명
시적으로 선언해줘야 한다.

이를 통해 코딩 에러를 예방하고 버전 유연성을 유지한다.

이러한 특징은 프로젝트의 나중 버전을 견고 하게 만들어 궁극적으로 전체 개발 비용의 절감 효과를 가져올 것이다.

호환성

C#은 호환성 측면에서 이전의 어떤 언어와도 비교할 수 없이 훌륭한 면모를 자랑한다.

C#은 닷넷 CLS(Common Language Specification)를 통해 윈도우 플랫폼의 네 종류의 API에 모두 접근할 수 있다.

여기서 CLS란 CLS 표준을 따르는 언어 사이에 상호 운용성 표준을 정의한 것으로, C# 컴파일러가 CLS에 따르도록 통제한다.
닷넷 플랫폼 런타임은 COM에 접근할 수 있도록 해주고, 레거시 코드와도 쉽게 통합할 수 있게 한다.

OLE automation API에 대해서도 접속할 수 있으며 모든 데이터형을 지원한다.
마지막으로 C#은 C타입 API와도 상호 운용될 수 있다.

이는 DLL의 어떤 엔트리 포인트도 C# 애플리케이션에 접근할 수 있다는 말이다.

만약 C#으로 개발시에 생산성이 더 높은 환경이 필요하다면 C++를 사용할 수도 있다.

C#에서는 모든 객체는 자동으로 COM객체가 된다.

개발자들은 더 이상 IUnknown 인터페이스와 다른 COM 인터페이스를 명시적으로 구현할 필요가 없다.

사용자 삽입 이미지

유연성

일부 애플리케이션은 성능상의 이유나 기존 API와 상호 운용하기 위해 원시 코드를 다뤄야 할 때가 있다.

WIN 32 원시코드에 접근하려면 때로 불안정한 포인터를 사용한다.

이때 개발자는 unsafe 클래스와 메쏘드 내부에서 포인터를 사용할 수 있다.

기본적으로 C# 코드는 safe 모드지만, 특정 클래스나 메쏘드만을 unsafe 모드로 선언할 수 있도록 허용한다.

이를 통해 개발자는 포인터와 구조체, static 배열을 사용할 수 있다.

단 unsafe 모드에서 메모리를 다루려면 가비지 컬렉터가 메모리 위치를 옮기지 않도록 메모리를 고정시켜야 한다.

unsafe

{

    fixed(int *ptrInt = &intObject)

    {

         Console.WriteLine(*ptrInt);

    }

}



C#의 실행 원리
C# 코드의 실행은 닷넷 프레임워크에서 제공되는 닷넷 런타임에 의해 관리된다.

C# 소스 코드가 작성된 후에 실행되기까지의 과정을 살펴보면 <그림 1>과 같다.
C# 소스코드를 컴파일하면 기존의 C++나 비주얼 베이직과 달리 직접 원시 코드(native code)를 생성하지 않고 IL(Intermediate Language)이 생성된다.

IL 코드란 CPU에 관계없이 닷넷 런타임이 설치되기만 하면 어떤 운영체제든지 실행될 수 있는 코드를 의미한다.

이것은 닷넷 런타임에 의해 관리되기 때문에 관리 코드(managed code)라고도 하며, 보통 EXE나 DLL 형태로 저장된다.

이 글의 ‘HelloWorld’예제에서 Hello.cs 파일을 컴파일하면 Hello.exe 파일로 변환/저장되는 것을 참조하기 바란다.
이렇게 변환된 EXE 또는 DLL 파일에는 IL 코드 이외에 메타 데이터가 생성, 저장돼 있다. 메타 데이터는 실행 코드 로드시 필요한 형 정보와 각 형의 메쏘드, 시그너처 정보, IL 코드가 참조하는 레퍼런스를 포함한다.

이것은 기존 COM의 타입 라이브러리와 레지스트리 엔트리에 해당하는 정보다.

이렇듯 메타 데이터와 IL 코드가 함께 .exe 나 .dll 파일로 저장된다는 것은 예전처럼 레지스트리를 건드리지 않고도 애플리케이션을 관리할 수 있음을 의미한다.

또한 메타 데이터 자체가 IL 코드가 참조하는 레퍼런스의 정확한 버전 정보를 명시하기 때문에 애플리케이션이 필요로 하는 버전의 DLL을 정확히 호출함으로써 관리의 어려움을 해소한다.
IL 코드와 자기 표현형 메타 데이터가 함께 패키징된 EXE 파일이 닷넷 런타임이 설치된 운영체제에서 실행되는 과정을 살펴보자.

먼저 닷넷 런타임이 실행 파일의 메타 데이터 정보를 로드하고, 그 정보를 토대로 닷넷 프레임워크에서 제공하는 클래스 라이브러리를 참조해 IL 코드에 있는 클래스를 로드하고 클래스의 인스턴스를 준비한다.
그리고 IL 코드를 실행 CPU 명령에 따라 원시 코드로 변환해 실행한다.  작업을 수행하는 것이 바로 닷넷 런타임에서 제공하는 JIT 컴파일러(Just In Time Compiler)다.

JIT 컴파일러는 IL 코드 전체를 한꺼번에 원시 코드로 변환하는 대신에 형이 요청될 때마다 로드해
원시 코드로 변환, 실행한다.


C#으로 작성한 Hello, World

자, 이제‘hello, world’를 화면에 출력하는 전통적인 콘솔 프로그램을 하나 작성해 보자.

아마 C#의 스팩을 공부했거나 혹은 그렇지 않더라도 일반적으로 프로그래밍 언어를 사용해 본 독자라면 금새 이해 할 수 있는 내용일 것이다.

메모장을 열고 다음과 같이 입력한 후 hello.cs라고 저장한다.

using System;


class Hello
{
    static void Main()
    {
        Console.WriteLine(“hello, world”);
    }
}

이 소스코드는 닷넷 SDK에서 제공하는 명령행 컴파일러를 사용해 다음과 같이 컴파일할 수 있다(물론 비주얼 스튜디오 닷넷의 콘솔 애플리케이션 프로젝트를 열어서 만들 수도 있다).

사용자 삽입 이미지


csc hello.cs


이 지시어는 hello.exe란 이름의 실행 프로그램을 만들고, 프로그램의 출력 결과는 <화면 1>과 같다.
지금부터 프로그램의 구체적인 의미를 살펴보자.

우선 using System;은 닷넷 프레임워크 클래스 라이브러리에 의해 제공되는 System이란 이름의 네임스페이스(namespace)를 참조하겠다고 선언하고 있다.

네임스페이스는 클래스 라이브러리의 요소를 구조화할 수 있는 계층적인 수단을 제공하는데, Main 메쏘드 내 Console 클래스를 포함하고 있다.

using 지시어를 사용하면 네임스페이스의 멤버인 형의 풀네임을 기술하지 않아도 그 형에 접근할 수 있으므로, 여기서는 System.Console.WriteLine라고 기술하지 않고 Console.WriteLine으로도 Console 클래스에 접근할 수 있다.
Main 메쏘드는 Hello 클래스의 멤버로 static 제한자를 갖고 있으며, Hello 클래스의 인스턴스라기 보다는 클래스 자체에 속한 메쏘드다.

프로그램의 주 엔트리 포인트(실행을 시작하기 위해 호출되는 메쏘드)는 항상 Main이란 이름의 static 메쏘드가 된다. ‘hello, world’ 라는 출력 결과는 클래스 라이브러리를 사용해 생성된다.

C# 언어 자체는 클래스 라이브러리를 제공하지 않는 대신 비주얼 베이직과 비주얼 C++같은 언어에서 사용되는 공통의 클래스 라이브러리를 사용한다.

C나 C++와 달리‘hello, world’프로그램에 나타나지 않는 몇가지 특징을 주목해보자.
◆ 프로그램은 Main 메쏘드에 대한 전역 메쏘드를 사용하지 않고, 변수는 전역 수준에서 지원되지 않는다. 이러한 요소들은 항상 형 선언부(class와 struct 선언부)에 포함된다.
◆ 프로그램에서 ::나 ->는 사용하지 않는다. ::는 연산자가 아니고, -> 연산자도 오직 프로그램의 일부에만 사용된다. “ .”연산자는 Console.WriteLine처럼 복합 이름에 사용된다.
◆ 프로그램은 전방 선언을 포함하지 않는다. 이는 더 이상 선언 순서가 중요하지 않기 때문이다.
◆ 프로그램이 프로그램 텍스트를 가져오기(import) 위해 #include를 사용하지 않는다.


C# 프로그램의 구조
그렇다면 C# 프로그램의 전체 구조는 어떻게 이뤄져 있을까.

우선 C# 프로그램은 하나 이상의 파일로 구성된다.

그리고 각 파일은 하나 이상의 네임스페이스를 포함하는데, 여기에는 클래스와 구조체, 인터
페이스, 열거형, 위임형뿐만 아니라 다른 네임스페이스도 포함할 수 있다.

<리스트 2>는 이러한 요소들을 모두 포함하는 C# 프로그램의 뼈대를 보여주고 있다.

사용자 삽입 이미지


C#으로 만드는 도서관리 프로그램
비주얼 스튜디오 닷넷에서 작성할 수 있는 C# 애플리케이션의 형태는 크게 네 가지로 나눌 수 있다.

즉 콘솔용 애플리케이션, 윈도우 애플리케이션, 웹 서비스 애플리케이션, 웹 서비스로 사용될 수
있는 컴포넌트가 이에 해당하는데, 아마도 대부분의 개발자들은 C#을 웹 서비스를 위한 애플리케이션 형태로 많이 사용하게 될 것이다.

이번 특집의 또 다른 내용인 ASP.NET도 C#의 형태일 수 있으며, 웹 서비스의 컴포넌트 형태로 작성될 수도 있다.

여기서는 비주얼 베이직의 높은 생산성과 유지보수 능력, 그리고 C나 C++의 강력한 성능을 C#과 비교하기 위해 윈도우 애플리케이션을 만들었다.

자바와 C#은 닮은꼴?

자바라는 언어가 처음 세상에 나왔을 때는 전자제품에 쓰여질 컴팩트한 디자인을 가진 프로그래밍 언어였다는 사실은 누구나 알고 있을 것이다. 당시 유행처럼 불어닥친 인터넷의 열풍 속에서 자바는 웹 사이트를 역동적으로표현할 수 있는 애플릿을 통해 무엇이든지 할 수 있는 것처럼 보였다. 하지만 나름대로 인고의 시간이 지나고 점차 모양새를 갖추면서 현재의 자바는 그 당시와는 판이하게 다른 거대한 솔루션으로 자리잡아 가고 있다. 이제
자바를 논하기 위해서는 자바라는 언어 자체보다는 거대한 자바 플랫폼에 다가서야 할 것이다. 기업용 자바 플랫폼인 J2EE는 자바만을 위한 최상의 환경이기 때문이다. 이러한 상황 속에서 MS는 자사의 모든 솔루션을 인터넷과 통신에 알맞은 모델로서 탈바꿈시키기 위해 닷넷이라는 새로운 프레임워크를 소개했다.


많은 전문가들은 향후 J2EE와 닷넷이 IT 시장의 대결구도를 형성할 것으로 예측하고 있다. J2EE의 핵심 언어가 당연히 자바라면 닷넷의 핵심언어는 무엇일까. MS에서 발표한 것처럼 C#이라는 새로운 언어가 그 자리를 차지할 것으로 예상된다. 새로운 언어의 등장은 개발자의 호기심을 불러 일으키는 법. 과연 C#은‘새로운’언어인가(C/C++와 사촌 관계인) 아니면 자바의 아들이라는 소문이 맞는 것일까?


닮은 꼴이라고 부르는 이유
객체지향 언어 : 자바와 C#은 모두 객체지향 언어로서 객체지향 언어의 특징인 은닉화, 상속성, 다형성을 지원한다. 특히 클래스의 상속은 C++와 달리 단일 상속을 지원하므로 개발자가 직관적으로 클래스의 구조를 파악할 수 있다. 다만 인터페이스 상속은 다중 상속을 허용한다.
플랫폼 독립적 : J2EE에서 자바는 플랫폼 독립적이다. 자바는 JVM(Java Virtual Machine)에 의해 실행되는 바이트 코드라는 중간 단계의 파일로 컴파일된다. 닷넷 플랫폼의 C# 역시 닷넷 CLR(Common Language Runtime)에 의해 실행되는 중간 단계의 언어인 MSIL(Microsoft Intermediate Language)로 컴파일돼 플랫폼에 독립적이다.
언어의 간결성 : 자바와 C#은 사용하기가 쉽다. 특히 C++와 달리 기본적으로 포인터를 사용하지 않는다.
가비지 컬렉션 제공 : 자바는 JVM에 의해 그리고 C#은 닷넷 CLR에 의해 프로그램 내에서 사용되지 않는 메모리 자원을 적절한 시간에 회수 한다. 더이상 개발자가 메모리 관리를 위해 신경을 쓰거나 형식적인 코드를 삽입하지 않아도 된다.
멀티 쓰레드 지원 : 자바와 C#은 언어 차원에서 쓰레드를 지원한다. 자바는 synchronized라는 키워드로 메쏘드와 클래스 차원의 Lock을 지원하고, C#에서는 Lock과 UnLock을 사용한 쓰레드 동기화를 직접적으로 지원해 손쉽게 쓰레드를 사용할 수 있다.
패키지화 : 자바와 C#은 기능적으로 비슷한 클래스와 인터페이스의 집합적인 단위를 제공한다. 자바에서는 패키지라고 부르고 C#에서는 이를 네임스페이스라고 한다.

우리는 서로 다르다
성능의 차이 : 자바는 기본적으로 JVM에 의해 해석, 실행되는 형태이고 MSIL은 해석과정이 필요없이 곧바로 컴파일된다.
다양한 언어 지원 : 자바는 J2EE 환경에서 오직 독보적인 프로그래밍 언어인데 반해 닷넷 환경에서는 닷넷을 지원하는 어떠한 언어라도 MSIL로 컴파일될 수 있다. 이렇게 컴파일된 클래스의 모든 자원은 여러 언어에 의해 공유되므로 다른 언어 사이의 디버깅 및 통합 환경을 제공 한다.
배포 : 자바는 동일한 소스라 할지라도 각 클래스 개수만큼 .class 파일이 별도로 생성되므로 배포에 어려움이 따르지만 C#에서 생성된 MSIL의 경우 하나의 DLL이나 EXE 파일에 여러 클래스가 포함돼 생성된다.
포인터 지원 : C#에서는 unsafe 모드를 통한 포인터 사용으로 시스템 API를 지원한다. 자바는 JNI(Java Native Interface)를 통해 지원할 수 있다.
다양한 형의 지원 : C#에서는 C++에서 사용하는 열거형을 지원한다. 이외에도 클래스와 구조가 유사하나 value 타입인 struct, 클래스에 대해 배열과 같은 접근을 허용하는 Indexer, 함수 포인터 역할을 하는 delegate를 지원한다.
명시적 오버라이딩 : C#에서는 가상 함수를 오버라이딩할 때 명시적으로 Override라는 키워드를 사용해야 한다. 이는 향후 부모 클래스가 변경됐을 경우 New라는 키워드와 함께 안전한 버전관리를 제공한다.
연산자 오버로딩 지원 : C#에서는 C++와 마찬가지로 연산자 오버로딩 기능을 제공하지만 사용할 수 있는 연산자가 제한된다. 기존에 정의된 형에 대한 연산자뿐 아니라, 사용자 정의 연산자도 사용할 수 있다.
원시형과 클래스형의 손쉬운 변환 : 자바와 C#은 모두 object라는 최상위 클래스에서 상속받는 개념인데 자바의 경우 원시형은 클래스형과 구분된다. C#에서는 원시형을 포함한 모든 형이 object로부터 상속받는다. 따라서 모든 형을 object형으로 변환할 수 있다.
위임형/이벤트를 사용한 이벤트 모델 : 자바에서는 리스너 인터페이스를 통해 이벤트를 처리하는데, 이 인터페이스는 특정 컨트롤(마우스, 윈도우 등)에 종속적인데 비해 C#에서는 위임형을 통해 처리한다. 위임형은 함수 포인터와 같은 개념으로 이벤트에 Delegate를 등록시키면서처리할 메쏘드를 명시한다.
사용자 정의 데이터형 정의 : C#에서는 사용자가 정의한 새로운 데이터형을 사용할 수 있다. 미리 정의된 Primitive 타입은 System 네임스페이스에 속한 Struct의 별칭이고, 사용자는 자신의 데이터형에 속성 및연산자 등을 포함시킬 수 있다.
Attribute를 이용한 선언적 프로그래밍 : C#은 자바에 존재하지 않는 Attribute를 지원한다. Attribute는 기존에 정의된 접근자(public,private) 외에 사용자가 명시적으로 선언 정보를 나타내는 것으로,Attribute 클래스로부터 상속받은 클래스를 사용해 정의할 수 있다.


<리스트> C#, 자바, 그리고 C++를 비교하기 위한 소스코드

// C#으로 작성된 코드
using System;

class HelloWorld

{
    static void Main()

    {
        for (int ii=1; ii <= 100; ii++)
        Console.WriteLine(“Hello World, repeated another{0} times.”, ii);
    }
}
// 자바로 작성된 코드
class HelloWorld

{
    public static void main(String[] args)

    {
        for (int ii=1; ii <= 100; ii++)
        System.out.println(“Hello World repeated another”+ii + “ times.”);
    }
}
// C++로 작성된 코드
#include <iostream.h>
int main()

{
    for (int ii=1; ii <= 100; ii++)
    cout << “Hello World, repeated another”<< ii << “times.”<< ‘\n’;
}

 
 

실무에서 확인받은 안정된 기능 다양한 언어지원

지난해 6월 MS가 닷넷 플랫폼의 핵심 언어로 발표한 C#은 현재까지 그 태생 배경과 가능성을 놓고 의견이 분분하다. 일부에서는 새로운 환경에 걸맞는 언어라며 높은 점수를 주기도 하고, 한편에서는 자바를 본따 만들어져 그다지 특별한 것이 없는데도 왜 이리 호들갑을 떠냐고 반문하기도 한다. 여러분의 생각은 어떠한가. 사실 5�6년의 역사를 가진 자바와 등장한 지 수 개월 밖에 되지않는 C#을 동일선에서 비교하는 것은 옳지 못하다. 하지만 이러한 일이 빈번히일어나고 있는 만큼 두 개의 언어를 제대로 아는 것이 무엇보다 중요하다고 판단, 편집팀은 대담 인터뷰를 마련했다. <박은정 기자>


마소 : 인터넷 시대에 가장 주목받는 프로그래밍 언어의 전문가로서 불리운다. 처음에 어떤 계기로 익히게 됐는가.

김덕태 : 프로그래머라면 누구나 그렇듯 초기에 C를 사용하다가 C++에 매력을 느끼기 시작했다. 그러던 중에 언어와 라이브러리를 구체적으로 배울 수 있는 자바에 관심을 갖기 시작했다. 사용할수록 자바는 강력하고 흡입력이 높은 언어임을 깨닫는다.
홍영준 : 언어를 자유자재로 조리하지 못하면 프로그래밍 자체에 두려움을 느끼는 습관을 갖고 있다. 그동안 사용했던C++는 언어간의 문법 간섭(템플릿, 오버로딩 등)이 심하고 복잡하다는 점, 자바의 경우 느린 성능과 유연하지 못한 마이그레이션 때문에 불만을 갖던 중에 새로운 가능성을 지닌 C#를 접하게 됐다.
마소 : C#의 계보를 어떻게 파악하고 있는가.
홍영준 : C#은 MS의 닷넷 플랫폼을 지원하기 위해 등장한 언어이다. C#은 C++와 매우 비슷해 그것을 익히는 데 오랜 시간이 걸리지 않았다. 간단한 구문, 형의 안정성뿐 아니라 컴포넌트 지향적인 특징을 갖고 있다.
김덕태 : 오히려 C#이 특징면에서 자바와 비슷한 점이 많다고 판단된다. 메모리를 자동으로 관리해주는 가비지 컬렉션의 등장이나, CLR(Common Language Runtime)을 통한 플랫폼 독립성을 꾀했다는 점에서 이를 잘 알 수있다.
홍영준 : C#의 개발 환경은 처음부터 언어 독립적으로 설계됐다. 현재 코볼부터 스킴까지 다양한 언어가 동작할 뿐만 아니라 언어간의 호환이 완벽하게 지원된다. 어떤 언어를 사용하더라도 닷넷 프레임워크가 제공하는 서비스를 접근할 수 있다는 말이다. 자바만 사용해야 하는 J2EE의 한계를 극복했다고 봐야 하지 않겠는가.
김덕태 : 물론 그렇다. C#은 윈도우뿐만 아니라 다른 운영체제에서도 C# CLR이 설치돼 있으면 컴파일러 없이 돌아가는 언어라고 표방하지만 자바만큼 ‘플랫폼 독립성’ 을 추구할 수 있을 것으로 보지 않는다. C#을 자바와는 달리 윈도우를 위한 특정 언어로 바라보는 관점이 우세한 것에 대해 어떻게 생각하는가.
홍영준 : 개인적으로 플랫폼 독립성의 실현 여부가 C#의 확산에 영향을 끼칠 것이라고 보지 않는다. C#은 그 자체로도 충분히 가치있는 언어다. 플랫폼 독립성과 언어의 가치는 별개의 문제라고 생각지 않는가. C#의 플랫폼 독립성은 C#에 의해서가 아니라 CLI 실행 환경이 얼마나 다른 플랫폼에 이식이 되느냐에 달려 있다. 이를 위해 MS는 리눅스와 유닉스에 닷넷을 포팅하고 있으며, 애플역시 닷넷 표준을 매킨토시에서 지원하겠다고 발표했다.

또한 C#은 이미 CLI와 함께 ECMA(유럽 컴퓨터 제조업자 협회)에 제출된 상태이고 올해 독립적인표준 기구의 승인을 받을 것이다. 초기에 C#이 MS에 의해 주도된 것이 사실이지
만 이제는 그들의 손을 떠났다고 봐야 할 것이다.
김덕태 : 라이브러리는 그 자체가 언어라고 할만큼 중요한 의미를 갖는다. JDK 1.3에 이르면서 표준 라이브러리 및 표준 확장 라이브러리가 상당히 방대해졌고 장기간에 걸쳐 다양한 플랫폼에 이식돼 왔다. 이는 자바의 채용에 대한 범 세계적인 공감대를 바탕으로 한 대규모의 투자라고 볼 수 있다. 닷넷이 플랫폼 독립성을 강조한다면 자바가 지향하는 바와 다를 바 없는 닷넷이 다시 자바만큼 공감대를 얻어 확산되리라고 볼 만한 근거가 무엇인가. 또 자바에서 기존의 컴포넌트를 SOAP을 통해 이용함으로써 자바 개발자를 끌어들일 것이라고 말했다. SOAP을 통해 기존의 컴포넌트를 얼마나 이용할 수 있는가.

홍영준: SOAP의 주목적이 서로 다른 플랫폼에 존재하는 기존 컴포넌트의 투명한 활용은 아니라고 생각한다. SOAP은 B2B 트랜잭션을 제어하는 수준이 될 것이며, 호환성이 중시됨으로써 기능과 성능의 저하는 피할 수 없는 문제이다.
김덕태 : 자바는 프로퍼티를 부담이 많이 가는 형식으로 지원하는 점이 불만스럽다. C#의 경우 편리한 사용자 정의 자료형, 다차원 배열 지원 등 편리한 점을 찾을 수 있다.

홍영준 : C#에서 지원하는 Delegate형은 C/C++의 함수 포인터와 비슷하며, GUI나 쓰레드 환경에서 다른 패러다임의 언어를 충분히 쉽게 접근할 수 있는 방향을 제시하고 있다. 또한 Event를 제공해 Event-Model이 비교적 간결하다. 그러나 무엇보다 C#의 가장 큰 특징은 Boxing/UnBoxing을 이용해 성능을 저해하지 않으면서 Smalltalk와 마찬가지로 모든 객체에 대한 일관적인 관점을 제시하고 Attribute를 이용해 객체와 실행환경과의 관계를 명시적으로 선언할 수 있다는 점이다.
마소 : C#과 자바의 미래를 어떻게 바라보는가.
김덕태 : 새로 등장한 언어인 C#을 주목할 필요는 있다고 본다. 닷넷 컴포넌트를 적극적으로 활용할 수 있다면 생산성과 시간면에서 향상을 꾀할 수 있기 때문이다. 그러나 C#과 닷넷의 내용 중 현실화되지 않은 부분이 많다는 점과 향후 자바 개발자의 수가 상당히 늘어날 것이라는 보고를 유념할 필요가 있다. 자바 개발자로서 현재 상황에서 C#에 시간을 투자하는 것은 시기상조라 본다.

홍영준 : C#의 미래는 밝다. 분명 닷넷 개발자에게 환영받는 언어가 될 것이다. 비주얼 베이직 언어 자체 혹은 기능에 불만을 가졌거나 C/C++의 복잡성에 염증을 느꼈다면 재빨리 C#으로 방향을 돌리기 바란다. 또한 윈도우에서 자바로 개발하던 사람도 C#을 익힐 만한 가치가 있다고 생각한다. 하지만 어떤 언어를 사용하느냐보다 문제의 특수성과 자신의 취향에 맞는 언어를 적절하게 선택하는 것이 가장 중요하지 않을까.


           <화면 2> C# 프로젝트를 새로 생성하는 화면

사용자 삽입 이미지

 

프로그램 개발 환경

도서관리 프로그램은 윈도우 2000 서버와 MS SQL 서버 2000 기반에서 MS 비주얼 스튜디오 닷넷 7.0 베타 1로 작성했다. 아직 베타 버전이므로 기존의 시스템에서 테스트할 경우 심각한 영향을 줄 수있으므로 새로운 테스트 서버에서 작성하길 바란다.


프로그램 개요

도서를 관리하기 위한 윈도우 애플리케이션용 프로그램으로 데이터 베이스에 저장된 도서에 대한 정보를 조회, 입력, 수정할 수 있다. 프로그램의 시작 단계에서 관리자 ID와 PASSWORD를 통한 인증을 거치고, 프로그램이 로딩되면서 데이터베이스에 저장된 정보를 읽어 들인다. 이 프로그램에서 데이터베이스로의 접근은 프로그램을 시작할 때와 변경된 데이터를 실제로 저장할 때에 이뤄진다. 여기서 저장 이란「File | Commit」메뉴를 클릭했을 때를 말하는데, 그전까지의 내용은 메모리에서 수정, 추가된다. 프로그램의 메인 윈도우가 로딩될 때 데이터베이스의 도서정보 는 DataSet으로 읽혀져 메모리에 상주하고, 도서정보를 추가, 수정, 삭제하는 작업은 데이터베이스와 직접 연동하는 것이 아니라 메모리에 상주된 DataSet을 변경한다. 이번 프로그램처럼 관리자용 애플리케이션에서는 성능에 별다른 차이가 없으나, 다중 사용자 환경인 웹이나 분산환경에서는 수행 속도에서 상당한 차이를 나타낸다. DataSet은 단순히 DataSource의 내용을 복사하는 것으로, 이후에는 DataSource와 단절돼 데이터의 유효성 문제가발생한다. 이러한 문제는 닷넷 프레임워크에서 테이블 사이의 종속 관계, 제약에 대한 설정을 통해 해결할 수 있다. 이제 비주얼 스튜디오 닷넷을 사용해 C# 프로젝트에 대해 설정하는 부분을 살펴보도록 하자.


C#프로그램 설정

먼저 비주얼 스튜디오 닷넷을 실행시키고, C# 프로젝트를 새로 생성 하기 위해「File | New Project」메뉴를 선택한다(<화면 2>). 프로젝트 선택 화면에서 느껴지는 각 언어 사이의 통합성은 프로
그램마다 참조하는 라이브러리가 따로 있는 것이 아니라 CLS를 통한 언어간의 통합성에서 기인한다. 현재 작업할 내용은 윈도우용 애플리케이션이기 때문에 <화면 3>과 같이 템플릿과 저장할 디렉토리등을 설정한다.
프로젝트를 열면 기본적으로 Design 화면이 나온다(<화면 4>). 이름은 기본으로 Form1.cs로 설정돼 있으며, 소스코드나 프로퍼티 창을 통해 수정할 수 있다. 소스코드는 프로그램 수행을 위한 기본적인내용만을 갖고 있으며, 주석 처리된 곳에 실제 구현할 프로그램 코드를 작성한다.
다음으로 프로그램에서 참조는 어떻게 이뤄지는지에 대해 알아 보겠다. 본 프로그램에서 사용되는 ADO.NET 등의 데이터와 관련된 네임스페이스인 System.Data와 System.Data.ADO를 사용하기 위
해서는 System.Data.Dll을 참조해야 한다. Project 탭에서 Add Reference를 선택하면 <화면 5>와 같은 화면이 뜨고 여기서 System.Data.Dll을 선택한다. 닷넷 프레임워크 SDK를 설치하고 도스 커맨드 창에서 참조하려면 다음과 같이 컴파일 옵션을 주고 컴파일한다.


csc /r:System.Data.Dll source_file_name


데이터베이스 디자인

데이터베이스는 세 개의 테이블, 즉 관리자 id와 password 정보를 가진 admin, 제품 분류에 대한 정보를 가진 BookClass, 도서에 대한 정보를 가진 Book으로 이뤄져 있다. BookClass와 Book 테이블은 서로 종속 관계를 가지며, Book 테이블은 BookClass의 ClassId 컬럼을 참조한다.

사용자 삽입 이미지

 

도서검색 및 수정 작업

전체적인 화면 구성은 탭으로 이뤄져 있다. 먼저 살펴볼 부분은 도서 검색/수정 부분이다. 화면 좌측에는 검색 메뉴가 나와있고, 우측에는 도서정보, 하단에는 수정 메뉴가 있다. 프로그램이 시작되면,데이터베이스로부터 도서에 대한 정보를 검색해 DataGrid에 뿌려준다.

사용자 삽입 이미지

도서정보 조회

앞서 언급된 것처럼 프로그램에서 데이터베이스와의 연동은 프로그램을 시작하고 저장할 때이다. 여기서는 MS SQL 2000과 연결하기 위해 ADOConnection 객체를 사용했다. ADOConnection은 관계형 데이터베이스뿐만 아니라 OLEDB를 준수하는 XML 형태로 표현될 수 있는 모든 소스에 접근할 수 있다. ADOConnection의 초기화는  기존 ADO와 마찬가지이고 옵션으로 DataBase Isolation level 등을 설정할 수 있다. 이외에도 SQLConnection 객체를 사용해 MS SQL 데이터베이스와 연결할 수 있다.

ADOConnection ACon=new ADOConnection(“Provider=SQLOLEDB.1;Data Source=localhost;uid=sa;pwd=;Initial Catalog=eshop”);

DataSource와 연결되면 데이터베이스로 쿼리를 수행해 데이터를 읽어오거나 DML(insert, update, delete) 작업을 수행할 수 있다. 닷넷 프레임워크에서 단순 쿼리의 경우 Command 객체가 아닌 DataSetCommand 객체를 사용하고, DML 작업의 경우 Command객체의 사용을 권장하고 있다. 다음은 ADODataSetCommand를 사용해 도서정보를 읽는 부분이다.

ADODataSetCommand ACom=new ADODataSetCommand(“select * from Book order
by BookId desc”, ACon);

ADODataSetCommand를 사용해 데이터를 가져오려면 데이터를 저장할 객체, 즉 앞서 설명한 DataSet이 필요하다. 기존의 ADO는 데이터를 가져오기 위해 RecordSet을 사용해 EOF(End of File)까
지 루프를 돌면서 값을 읽었으나 ADO.NET에서는 DataSet을 이용해 다중 테이블을 메모리에 저장한다. ADODataSet Command 객체를 이용해 생성한 DataSet에 데이터를 저장하는 구문은 다음과 같다.

DataSet ds=new DataSet();
ACom.FillDataSet(ds,”Book”);

첫 줄에서는 새로운 Data Set 객체를 생성했고, 두 번째 줄에서 DataSet에 Book이라는 이름으로 데이터를 저장했다. 이제 도서분류 정보를 읽기 위해 DataSet에 테이블을 하나 더 추가하고, 두 테이블에 종속 관계와 제약 조건을 설정하는 부분을 살펴보겠다. 연결이 끊긴 데이터의 유효성을 보장하기 위해 DataSet에는 Rela tions 객체와 제어를 설정할 수 있는 Property를 포함하고 있다. 다음은 BookClass(도서분류)를 DataSet에 포함하고 기존의 Book 테이블과의 종속관계를 포함시키는 부분이다.

ACom.SelectCommand.CommandText=”select * from BookClass order by ClassId desc”;
ACom.FillDataSet(ds, “BookClass”);
ds.Relations.Add(“CustOrders”, ds.Tables[“Customers”].Columns[“CustID”],

ds.Tables[“Orders”].Columns[“CustID”]);

<그림 3>에서 볼 수 있듯 DataSet에는 RelationsCollection 객체가 포함된다. 이 객체는 DataSet에 있는 DataTable 사이의 관계를 설정 한다. 앞의 코드에서는 DataSet에 BookClass 테이블을 새롭게 포함시켰고, 기존에 존재하던 Book 테이블과의 관계를 관계형 데이터베이스와 같은 방식으로 설정하면서 그 관계의 이름을‘CustOrders’라고 명명했다. 제품 ID와 제품 분류 ID를 데이터베이스에 각각 primary, identity로 설정하고, DataSet 객체 내부에서도 적용하기 위해 constraints를 설정한다.

ds.Tables[“Book”].Columns[“BookId”].AutoIncrement=true;
ds.Tables[“Book”].Columns[“BookId”].AutoIncrementSeed=maxbookid;
ds.Tables[“BookClass”].Columns[“ClassId”].AutoIncrement=true;
ds.Tables[“BookClass”].Columns[“ClassId”].AutoIncrementSeed=maxclsid;

DataSet의 각 컬럼에 대해서도 Constraint를 설정할 수 있다. 코드에서는 자동 증가 컬럼으로 설정하고 증가값(seed)을 지정했다. 이외에도 DataSource에 접근하기 위해 DataReader를 사용하는데, 이것은 ADO의 RecordSet과 같은 개념으로, 읽어들일 데이터의 양이 많지 않다면 DataSet보다 속도면에서 두 배 이상 빠르다. 따라서 성능이 중요한 경우라면 DataReader객체를 사용할 것인지에 대해 신중히 고려할 필요가 있다.다음은 DataSet으로 불러들인 데이터를 Grid에 뿌려주는 코드이다. 이것은 도서정보와 분류정보를 갖는 DataSet의 뷰를 생성하고,두 테이블 중에서 Book 테이블의 정보만 Grid에 보여준다.

this.dataGrid1.DataSource=dv;
this.dataGrid1.DataMember=”Book”;


도서정보 검색

DataSet에서 읽은 정보를 제목, 출판사, 저자에 대해 검색할 수 있도록 설정했다. 검색은 데이터베이스가 아닌 메모리 내에서 이뤄지므로 속도가 빠르다. 아직 데이터베이스에 저장되지 않은 상태이므로 Uncommitted Read와 같다. 사용자가 검색분류를 선택하고 하단의 검색어를 입력했을 때의 코드는 다음과 같다.

DataSetView dv=new DataSetView(this.SuperDS);
string selection=this.CategoryCombo.Text;


if(selection==”제목”)
    {
        selection=”Title”;
    }

     else if(selection==”출판사”)
    {
        selection=”Company”;
    }

     else if(selection==”저자”)
    {
        selection=”Author”;
    }

TableSetting ts = new TableSetting(dv.DataSet.Tables[“Book”],“BookId desc”,selection+”like ‘%”+ this.SearchText.Text.Trim()+”%’”, DataViewRowState.CurrentRows);
dv.TableSettings.Add(ts);

사용자 삽입 이미지

먼저 사용자가 선택한 분류를 검색하고 이를 실제 DataSet의 컬럼명과 일치시킨다. 하부에서는 데이터를 DataGrid에 뿌려주기 위해 DataView에 대한 필터링 작업을 수행하는데, 이것은 SQL의 쿼리문과 비슷하다. DataView는 DataSet의 내용을 보여주는 관계형 데이터베이스의 뷰와 같은 개념으로 DataGrid에 값을 뿌려주기 위해 정렬이나 필터링의 특징을 제공한다. DataTable의 컬럼에 대한 primary key constraint를 정의했다면, 이 키값을 사용해 데이터를 검색할 수도 있다. RowsCollection의 Find 메쏘드가 그것인데, 형식은 다음과 같다. 여기서 파라미터인 키는 1차의 키값을 나타내고 리턴되는 값은 그 키 값을 가진 DataRow이다.

public DataRow Find(object key);


도서정보 수정

도서 ID를 입력하고 탭키를 누르면 ID에 해당하는 정보를 사용자에게 보여준다. 정보를 수정하고‘수정’버튼을 클릭하면 변경된 정보가 DataSet에 입력되고, 이 정보를 키에 출력한다. 프로그램의 첫 번째 Grid는 현재 DataSet에 있는 정보를 출력하고, 두 번째 Grid는 새로 추가되거나 변경된 정보를 출력한다.

dr[“Title”]=f.UpTitleBox.Text;
dr[“Price”]=System.Int32.Parse(f.UpPriceText.Text);
dr[“SPrice”]=System.Int32.Parse(f.UpSPriceText.Text);
dr[“Company”]=f.UpCompanyText.Text;
dr[“Author”]=f.UpAuthorText.Text;
dr[“IsSale”]=(bool)f.UpIsSaleCombo.Checked;


도서관리 입력
도서정보 입력에 앞서 도서분류 정보를 추가한다. 도서정보 수정과 마찬가지로 도서입력도 DataSet에 정보를 넣는다. <화면 8>을 보면 상단에는 도서정보 추가부가, 하단에는 분류 추가부가 있다. 분류명을 입력하고‘확인’단추를 클릭하면, DataSet 내부의 Book Class에 분류명과 identity로 설정된 ClassId에 자동 증가값이 입력된다.
사용자 삽입 이미지

DataRow dr=ds.Tables[“BookClass”].NewRow();
dr[“ClassName”]=BookClassText.Text;
ds.Tables[“BookClass”].Rows.Add(dr);

도서분류를 입력한 후에 도서정보에서 해당 분류를 ComboBox에서 선택하고 나머지 정보를 추가한 다음‘저장’버튼을 클릭한다. 그러면 정보는 DataSet의 Book 테이블에 저장된다.

DataRow dr=this.SuperDS.Tables[“Book”].NewRow();
dr[“Title”]=this.TitleText.Text;
dr[“Price”]=System.Int32.Parse(this.PriceText.Text);
dr[“SPrice”]=System.Int32.Parse(this.SPriceText.Text);
dr[“Company”]=this.CompanyText.Text;
dr[“Image”]=this.ImageText.Text;
dr[“Author”]=this.AuthorText.Text;
dr[“Date”]=this.DateLabel.Text;

// 판매중인지 아닌지를 체크한다(checkbox).
if(this.checkBox1.Checked)
{
    dr[“IsSale”]=1;
}

else
{
    dr[“IsSale”]=0;
}

// 클래스 아이디 찾기
int clsid=(this.comboBox1.SelectedIndex);
string ISName=((string)this.SuperDS.Tables[“BookClass”].Rows[clsid][“ClassName”]);
foreach(DataRow myrow in this.SuperDS.Tables[“BookClass”].Rows)
{
    string find=((string)myrow[“ClassName”]).Trim();
    if(find.Equals(clsName))
    {
        dr[“ClassId”]=myrow[“ClassId”];
    }
}
this.SuperDS.Tables[“Book”].Rows.Add(dr);


도서관리 저장

사용자가 파일 메뉴의 Commit을 클릭하면 메모리의 정보가 데이터 베이스에 저장된다. 보통 저장 프로시저를 생성하고 Command 객체를 사용해 데이터베이스에 저장하는데, 관련된 프로시저의 정의는 다음과 같다.

create proc UpData
@BookId int,
@Title varchar(50),
@Price int,
@SPrice int,
@Company varchar(20), @Author varchar(20), @IsSale bit
as
update Book
set
Title=@Title, Price=@Price, SPrice=@SPrice, Company=@Company,Author=@Author,IsSale=@IsSale
where BookId=@BookId

다음은 프로그램에서 저장 프로시저의 사용을 보이는 소스코드다.

ADOParameter PBookId=AComm.Parameters.Add(“@BookId”,ADODBType.VarChar,30);
ADOParameter PTitle=AComm.Parameters.Add(
“@Title”,ADODBType.VarChar,50);
ADOParameter PPrice=AComm.Parameters.Add(
“@Price”,ADODBType.Integer);
ADOParameter PSPrice=AComm.Parameters.Add(
“@SPrice”,ADODBType.Integer);
ADOParameter PCompany=AComm.Parameters.Add(
“@Company”,ADODBType.VarChar,20);
ADOParameter PAuthor=AComm.Parameters.Add(
“@Author”,ADODBType.VarChar,20);
ADOParameter PIsSale=AComm.Parameters.Add(
“@IsSale”,ADODBType.Boolean);

try

{
    ACon.Open();

    foreach(DataRow irow in rowcol)
    {
        PBookId.Value=(System.Int32)irow[“BookId”];
        PTitle.Value=(string)irow[“Title”];
        PPrice.Value=(System.Int32)irow[“Price”];
        PSPrice.Value=(System.Int32)irow[“SPrice”];
        PCompany.Value =(string)irow[“Company”];
        PAuthor.Value=(string)irow[“Author”];
        PIsSale.Value=(bool)irow[“IsSale”];
        AComm.ExecuteNonQuery();
    }
}

catch(Exception e)
{
    System.WinForms.MessageBox.Show(e.ToString());
    return;
}

finally
{
    ACon.Close();
}

사용자 삽입 이미지

ADOCommand 객체를 사용해 저장 프로시저를 실행시키기 위한 방법은 기존 ADO에서 사용하던 방법과 크게 다르지 않다. 먼저 ADOCommand 객체의 ParameterCollection에 파라미터를 추가한다. 추가시에는 파라미터명(프로시저의 파라미터명과 동일), 파라미터의 형, 길이를 명시한다. 파라미터의 기본값은 입력돼 있기 때문에명시하지 않았으나, 출력 파라미터를 지정하는 경우에는 다음과 같이작성한다.

APara.Direction=ParameterDirection.Output;

ADODataSetCommand는 자동으로 Connection이 열리지만 ADOCommand에서는 명시적으로 Connection을 열어줘야 한다. Open 부분을 try문으로 감싼 것은 Open이 InvalidOperationException을 발생시킬 가능성이 있기 때문이다. 실제로 예외가 발생했을 경우에는 catch절로 이동해 예외명을 다이얼로그 박스로 출력하게 된다. 파라미터의 Direction(입∙출력)을 설정했다면 이후에는 입력 파라미터인 경우 값을 할당해야 한다. 예제에서는 DataTable의 Rows Collection을 이용해 값을 할당했다. 이때 RowsCollection에서 각각의 DataRow에 접근하는 것은 indexer를 사용했는데, 이러한 경우에는 컬럼명을 할당하거나 컬럼의 인덱스를 System.Int32형으로 할당할 수 있다.

마지막으로 데이터베이스 저장 로직을 설명하면 BookClass가 상위 테이블이므로 Book 테이블보다 앞서 저장해야 한다. 메모리에 두테이블이 있는 상태에서 데이터베이스에 Book 테이블이 먼저 저장된다면 Book 테이블이 참조하고 있는 ClassId가 메모리에는 존재하지만 실제로 데이터베이스에 존재하지 않을 경우에는 참조 무결성에 위배돼 에러가 발생하기 때문이다. 삭제하는 로직은 역순으로 작성하면된다.


이벤트 처리

C#에서의 이벤트는 Delegate를 통해 처리한다. Delegate는 이벤트가 발생했을 때 이를 처리할 메쏘드를 가지고 있는 함수 포인터 개념이다. Delegate에는 정적 메쏘드나 인스턴스 메쏘드가 모두 올 수있다. 비주얼 스튜디오 닷넷의 class View를 통해 확인하면 <화면9>와 같이 button1이 button1_Click이라는 메쏘드에 연결된 것을알 수 있다.
이벤트 처리를 위해서는 이벤트에 Delegate를 등록해야 한다. 그러면 그 Delegate의 생성자 파라미터로 실제 실행될 메소드의 이름이들어가게 된다. 이때 메쏘드와 Delegate의 시그너처는 동일해야 하고, 등록한 이후에는 실제 버튼을 클릭하면 해당하는 메쏘드에서 이벤트를 처리한다.

button1.Click += new System.EventHandler(this.button1_Click);

사실 한정된 지면에서 모든 것을 다루는 것은 쉽지 않은 일이다. ‘이달의 디스켓’으로 제공되는 소스를 실행시켜 자세한 동작원리를 직접 살펴보는 것이 좋은방법이 될 것이다. 소스는 살펴보기 쉽도록 주석처리했다. 아마도 이 프로그램 코드를 살펴보면 UI가 그다지 좋지 못한 것을 발견할 것이다. 또한 원하는 기능이나 일부 기능이 빠졌을 수도 있다. 필자는 이 소스코드를 바탕으로 한 더욱 향상된 프로그램의 탄생을 독자 여러분에게 숙제고 남기고 싶다.


ADO와 ADO.NET의 비교

MS는 윈도우 NT 시절에 관계형 데이터베이스를 필두로 한 구조형 데이터 베이스와 SAM 파일과 같은 준구조화 데이터베이스, 문서나 멀티미디어 데이터, 메일 메시지와 같은 비구조화 데이터를 통합해 접근할 수 있는UDA(Universal Data Access)라는 아키텍처를 제시했다. 또한 UDA 환경에서 개발자가 좀 더 편리하게 사용할 수 있도록 MDAC(Microsoft Data Access Component)라는 컴포넌트를 제공하고 있다. MDAC는 ODBC, OLEDB, RDS, ADO 등 다양한 종류의 데이터 접근 객체로 이뤄져 있는데, 이중에서 ADO는 비주얼 베이직과 같은 RAD 환경에서 주로 사용되고 있으며 이를 통해 손쉽게 클라이언트/서버 모델을 구현하고 있다.

ADO의 가장 대표적인 객체로는 Connection, Command, Recordset을 들 수 있다. Connection 객체는 주로 DataSource에 연결하기 위한 목적으로 사용되며, Command 객체는 RDB(Relation DataBase)에서 제공하는 저장 프로시저나 SQL 명령을 수행하기 위해 사용된다. Recordset 객체는 SQL 질의를 통해 커서를 생성하고 데이터의 네비게이션을 위한 조회용으로 주로 사용된다. 또한 ADO.NET에서는 주로 DataSet이라는 새로운 개념의 객체를 사용한다. 이것은 데이터베이스의 복사본, 즉 연결이 끊어진하나의 데이터베이스와 같으며 DataRelation 객체를 통해 DataTable의 관계를 표현할 수 있다. 이러한 DataSet은 XML로 변환해 어떠한 계층으로도 전달해 사용할 수 있다.
ADO의 Recordset 객체는 ADO 2.0에서 Disconnected Recordset을 통해 연결이 끊어진 상태에서 클라이언트 캐시 메모리를 통해 데이터를 처리할 수 있는 방법을 제시했다. 또 ADO 2.5에서는 Stream 객체를 통해 XML 형태로 데이터를 분산처리했다. 하지만 이러한 것들은 COM 마샬링을 통해 처리되거나 송신자와 수신자가 같은 ADO일 경우에만 제대로 동작 한다는 제약이 따른다. 따라서 Recorset 객체를 통한 데이터를 다른 플랫폼의 특정 수신자에게 전달하려면 굉장히 번거로운 절차가 필요할 것이다.
ADO.NET은 이러한 측면에서 상호 운영성과 확장성을 제공하고 있다. ADO.NET의 모든 데이터는 XML 기반으로 완벽히 처리되고 있으며, COM 마샬링 없이 데이터를 인터넷에서 분산 처리할 수 있다. 이러한 마샬링 처리의 오버헤드를 없앰으로써 더 뛰어난 성능을 제공한다. ADO의 Recordset 객체는 하나의 테이블과 같은 엔터티를 통해 데이터를 컬렉션으로 표시하지만 ADO.NET의 DataSet은 데이터 자체를 저장하고 있는 데이터베이스로 인식된다. 또한 DataReader 객체를 통해 기존의 Recordset과같은 프로그램 방식을 제공하고 있다. 다음은 DataReader를 기존 Recordset 방식과 같은 형태로 작성한 코드다.


ADOConnection adoCon = new SQLConnection(“Provider=SQLOLEDB.1;
Data Source=localhost;uid=sa;pwd=;Initial Catalog=eshop”);
ADOCommand adoCmd = new ADOCommand(“Select * from Book”, adoCon);
DataReader dbReader = null;
adoCon.Open();
adoCmd.Execute(out dbReader);
if (dbReader != null)
while (dbReader.Read())
// 필요 작업

ADO의 Connection에 해당하는 객체로 ADO.NET의 ADOConnection을 사용할 수 있으며, 사용방법은 거의 유사하다. 또한 ADO의Command에 해당되는 객체인 ADO.NET의 ADOCommand 객체는 데
이터를 조회해 DataReader 객체에 저장하거나 데이터베이스의 데이터를 입력, 수정, 삭제할 수 있다. <그림 1>은 ADO.NET의 구조도다.

ADO.NET의 관리 프로바이더는 SQL 관리 프로바이더와 ADO 프로바이더로 분류된다. SQLDataSetCommand 등과 같이 SQL로 시작되는 이름을 가진 객체들은 SQL1 서버 7.0 이상의 제품을 사용하는 관리 프로바이더이며 System.Data.SQL의 네임스페이스를 통해 참조된다. ADO 관리 프로바이더는 System.Data.ADO의 네임스페이스에 의해 참조되며, 다양한 OLEDB 프로바이더를 통해 사용된다.
코드를 작성하는 방법론적인 입장에서 살펴보면 기존의 ADO와 ADO.NET의 프로그램 패턴은 거의 비슷하다. 프로그램 입장에서 기존의 ADO 데이터는 항상 Fields라는 컬렉션을 통해 접근했으나
ADO.NET에서는 Strongly Typed Programming을 통해 저장된 데이터를 직접 프로그램에서 사용할 수 있는 특징이 있다. 이를 통해 개발자들은 더욱 직관적으로 데이터베이스를 프로그램 코드로 작성할 수 있다.

사용자 삽입 이미지


"새술은 새부대에"

인터넷의 발전과 더불어 과거에 상당히 다양했던 플랫폼이 이제는 웹과 통합되는 환경으로 점차 바뀌고 있다. 이러한 흐름에 맞춰 MS는 자사의 모든 플랫폼을 인터넷에서 더욱 편리하고 쉽게 구현해 사용할 수 있는 닷넷이라는 새로운 플랫폼을 제시하고 있다. ‘새 술은새 부대에’라는 말이 있듯이 새로운 플랫폼에서 동작할 수 있는 새로운 개념의 애플리케이션을 구현하기 위한 새로운 언어로서 C#이 등장했다. 물론 기존의 비주얼 베이직이나 C++같은 언어도 진보된 형태로 제공되고 있지만 이들은 과거의 플랫폼과의 호환성 여부 등 100% 완전히 새로운 플랫폼에 걸맞는 언어가 아니라고 여겨진다.

과거 썬의 제임스 고슬링에 의해 자바라는 새로운 언어가 등장했을 때만큼 필자는 가슴이 설렌다. 그 당시는 미래 가능성으로서 자바를 바라봤지만 C#은 MS 닷넷이라는 현실성이 매우 높은 플랫폼에서 사용될 수 있는 최상의 언어이기 때문이다.
아마 몇 년 이내로 C#은 MS 닷넷의 가장 인기있는 프로그래밍 언어이자 가장 많은 개발자가 사용하는 프로그래밍 언어가 될 것이다. 아직 확정된 스펙이 아닌 환경에서 C#을 학습하는 개발자가 상당히 많은 어려움을겪고 있을 것으로 예상된다. 하지만 C#은 개발자 스스로의 경쟁력을 한차원 더 높이기 위한 확실한 보증수표라는 말로 이 글의 말미를 대신한다.

<참고자료>

� Presenting C#, Christopher Wille, 맥스플러스 기술 번역,아이북스
� MSDN C# Language Specification
� Microsoft .NET Beta Documentation




정리를 하다 보니.. 약간 시간이 오래 된지라. 버젼이 틀립니다.

정리 시간도 길고 해서 지금의 2003버젼으로 변환 하진 못했습니다..

그리 큰 차이는 없습니다만, 혹시 본문의 어플리케이션을 만들고 싶다면 약간의 수정이 불가피 합니다. 본문에서처럼 독자 몫으로..

아무튼 C#에 대한 일반적인 얘기에 촛점을 맞춰 보시기 바랍니다.. 뭐 다알고 있으시겠지만요.. ^^;

반응형
Posted by Real_G