by 라피 크리코리안(Raffi Krikorian), 역 한빛 리포터 1기 신동섭
C#의 수석 설계자인 앤더스 헤일스버그(Anders Hejlsberg)는 객체지향적이며 컴포넌트 지향적인 언어를 디자인하는 것이 주요 목표였으며 어떻게 구현할 지 방향을 설정하기 위해 다른 언어들도 많이 보아 왔다. 다행히도 자바 프로그래머를 위해, C++와 자바를 연구했기 때문에, 자바 프로그래머라면 C#을 다루는 데 금방 익숙해질 수 있다. C#과 자바의 기본 개념과 문법이 아주 비슷하기 때문이다.
밀접한 관계가 있는 두 프로그램
C#을 속성으로 익히기 위해 가장 좋은 방법은 토이 자바 프로젝트를 C#언어로 바꾸어보는 것이다.
Hello.java로 과정을 시작해보자.
package com.oreilly.hello;
import java.io.*;
/**
* a simple application that we are going to port
* to c# as a demonstration
*
* @author Raffi Krikorian
*/
public class Hello
extends Object {
/**
* the entry point into this class -- this
* class will ask the user for his name, then
* reply to it
*
* @param args the command line arguments
*/
public static void main( String[] args ) {
// the name we are going to say hello to
String name = null;
// if the name is not on the command line,
// then we ask to read it off standard in
if( args.length == 0 )
try {
System.out.print( "Name? " );
// read from standard in
BufferedReader reader =
new
feredReader(
new InputStreamReader(
System.in ) );
name =
reader.readLine();
} catch( IOException error ) {
System.err.println
(
"Problem with input stream" );
error.printStackTrace();
System.exit( 1 );
}
else {
// take the name off the command line
StringBuffer buffer = new StringBuffer();
for( int count=0;
count |
처음으로 자바를 배웠을 때(처음에는 필수적으로 "Hello World"로 시작한다.) 구현했던 두 번째 자바 프로그램을 수정한 버전이다. 이 프로그램은 아주 평범한 것으로 처음 실행할 때 User name을 물어보며 명령어 라인에 입력하면 "Hello
, welcome to Java"를 디스플레이한다.
그러면 지금부터 파일명이 Hello.cs(이 코드는 마이크로소프트.닷넷 SDK 베타 1을 이용하여 구현, 컴파일 되었다)인 C#로 같은 프로그램을 작성해 보자.
using System;
using System.IO;
using System.Text;
namespace com.oreilly.hello {
///
/// a simple application that was ported from
/// java to c#
///
public class Hello : Object {
///
/// the entry point into this class --
/// this class will ask the
/// user for his name, then reply to it
///
/// the command line
/// arguments
///
/// 0 if everything goes well, 1 if
/// there is an error
///
static int Main( string[] args ) {
// name we are going to say hello to
string name;
// if the name is not on the command
// line, then we ask to read it off
// standard in
if( args.Length == 0 )
try {
Console.Write( "Name? " );
// read from standard in
name = Console.ReadLine();
} catch( IOException error ) {
Console.Error.WriteLine(
"
Problem with input stream" );
sole.Error.WriteLine(
error.StackTrace );
return 1;
}
else {
// take the name off the command
// line
StringBuilder buffer =
new StringBuilder();
foreach( string arg in args ) {
buffer.Append( arg );
buffer.Append( " " );
}
buffer.Length = buffer.Length - 1;
name = buffer.ToString();
}
// echo the name to the screen
Console.Write( "Hello " + name + "," );
Console.WriteLine( " welcome to C#" );
return 0;
}
}
}
|
눈에 띄게 비슷하지 않은가?
비교 분석
소스 파일
소스코드로 들어가서 이 프로그램을 분석해 보기로 하자. 자바에서는, 각각의 클래스가 지정된 파일(일반적으로 확장자가 .java)에 있어야 한다. 물론, 다른 클래스의 .java 파일 안에 정의되는 등, 클래스 변수와 내부 클래스를 가진 예외도 있다. C#은 클래스를 정의할 때, 다른 이름공간(namespace) 안에 있으면 이러한 제약이 없다. C# 프로그램의 어떠한 부분이라도 독립적인 유니트를 형성하기 위해서 같은 .cs 파일 안에 있을 수 없다.
이름 규약
모든 자바 프로그램은 항상 mixed-caps라는 하나의 표준 이름 명명 규약을 따른다(규약은 컴파일러에서 강제되는 사항은 아니지만, 자바 언어 설계에는 규약이 간단히 나타나며 프로그래머가 사용하는 스타일을 제공한다. 이러한 규칙에는 개발자 예외사항이 있다). mixed-caps 스타일은 하나의 이름 안에 지역적으로 분리된 곳에 스페이스나 밑줄을 사용하지 않는 대신, 대문자를 사용한다. 객체 이름은 첫 문자를 대문자로 표시하며 나머지부분엔 윔피(wimpy) 대문자를 쓴다. 예를 들면 ThisIsAnObjectName같은 식이다. 하나의 메소드 또는 변수를 나타내는 첫번째 문자는 보통 소문자이며 지역적으로 분리되는 경우엔 대문자로 표시한다(thisIsAMethodName, thisIsAVariableName). 물론, 명명된 변수(정적 최종 변수)는 이 규칙을 따르지 않는 것도 있으며 자바에서는 THISISACONSTANT와 같이 모두 대문자로 된 이름이 필요할 때도 있다.
메소드 이름이 첫번째 글자가 대문자라는 점을 제외하면 C#은 이러한 mixed-caps 스타일을 따른다. BCL(Base Class Library)에 사용되는 변수는 대부분 사용자 정의 변수 중 첫번째 문자가 소문자로 정의되었다 해도, 일반적으로 첫번째 문자는 대문자로 시작한다. 둘 다 mixed caps를 사용하기 때문에 이름 규약 상수와 할당 가능한 변수사이에 두드러진 차이점은 없다.
패키지/이름공간
자바 패키지는 구조를 체계적으로 만들고 신뢰성을 높이기 위해 다른 저자 정의 이름공간에 클래스를 두고 있다. 경험상 서로 관련된 클래스가 같은 패키지에 들어간다(그리고 하위패키지에는 밀접한 관련이 있는 클래스가 있다). 코더는 관련된 기능을 구현할 수 있는 클래스를 사용하기 위해 특별한 패키지 내부를 찾아볼 수 있다. 자바에서 패키지 안에 있는 클래스를 사용하기 위해, "완전하게 조건이 갖추어진 이름"(java.io.BufferedReader 등)을 코드 내에 표현할 수 있거나, 클래스 소스의 제일 위쪽에 "import"문을 사용하는 이름공간에 완전한 패키지나 특정 클래스를 임포팅(import)할 수 있다. JRE가 제공하는 모든 표준 클래스는 자바 패키지로 나누어진다.
C#도 이름 분할 구조가 비슷하다. 서로 다른 이름공간의 범위를 정하기 위해 하나의 이름공간 블록을 지정한다. Hello.cs 파일에서, 이름공간 com.oreilly.hello블록은 괄호 안의 모든 코드를 com.oreilly.hello "패키지"에 할당한다. 위의 예제서는 이러한 이름공간이 놓여질 수도 있다는 것이 표현되지 않는다. 예를 들면, 위의 이름공간은 아래와 같이 다른 구조가 같은 소스 파일 안에 다른 이름공간 안에 놓일 수 있는 형식으로 정의할 수 있다.
namespace com {
namespace oreilly {
namespace hello {
}
}
}
|
C#의 "using"문을 사용하면, 완전하게 구체화시킨 이름공간이 프로그램의 공간이 된다. 이는 자바의 "import"구문과 기능이 정확히 똑같지 않으며, 구체화된 객체를 프로그램의 이름공간이 되게 할 수 없다.
객체 만들기
자바의 클래스가 모두 java.lang.Object 클래스에서 파생된 것처럼, C#의 모든 클래스는 System.Object 클래스에서 파생되었다. 자바에서처럼 클래스가 객체를 확장한다면, 소스 코드안에 이를 구현할 필요가 없다. 클래스를 확장할 때, ":"을 사용한다(자바에서는 "extends" 키워드 사용). 위의 예제에서, C# Hello 클래스의 완전한 이름은 이름공간에 정의한 것처럼 com.oreilly.hello.Hello이다. 인터페이스를 구현하는 방법에 대해서는 위에서 살펴보지 못했다. 자바를 사용하면 코드가 다른 객체("extends"키워드를 통해)를 확장할 때나 인터페이스("implements"키워드를 통해)를 구현할 때를 확실히 구별한다. C#은 자바와 C++이 섞여 있기 때문에 자바 프로그래머는 짜증이 날 수도 있다. C#에서 인터페이스는 콜론(:)뒤에 놓일 수도 있고 컴파일러에서는 확장된 클래스가 콜론 뒤의 첫번째에 놓여야 한다.
class ClassName : ExtendedClass, Interface1, Interface2, ...
|
C#에서 클래스를 위한 기본 접근 변경자(default access modifier)는 이것을 정의한 .cs 파일 밖에서는 다른 객체가 접근하지 못하도록 하는 "internal"로 만드는 것이다. "protected"와 "internal"특징을 결합한 다섯번째 "protected internal"변경자에 더하여 더 많이 알려진 "public", "private", "protected"변경자를 제공한다(변경된 것을 enclosing class를 확장하는 클래스로부터 또는 정의된 파일 안에서부터 접근될 수 있다). 위의 Hello 예제에서, 그렇게 할 필요가 없다고 해도 자바와 C#클래스를 "public"으로 정의한다. 어떠한 클래스도 다른 객체가 사용하길 원하는 기능 등을 제공하지 않으며, 단지 실행 환경에서 실행될 수 있도록 하기위해 알맞은 시그너처를 제공한다.
시작점(Entry Point)과 종료점(Exit Point) 제공
클래스를 로드하고 시작하는 런타임 환경을 위해, 무엇부터 해야 할지 알아야 한다. 자바 언어는 JVM(자바 가상 머신)이 명령어 열 독립 변수들은 메소드로 될 수도 있도록 하기 위해 프로그래머가 public static void main(String[] args )메소드를 정의하고 프로그램을 시작한다. 좀더 유연성을 가지기 위하여 C#은 시작점을 위한 3가지 다른 메소드 시그너처(signature)를 제공한다. 가장 간단한 것으로 public static void Main() 메소드가 있다. 이것은 public static void Main( string[] args )과 public static int Main( string[] args )" 메소드의 결과로 일어난다. 나머지 두개의 시그너처는 명령어 열 독립 변수들을 프로그램으로 받아들인다. 그리고 세번째 시그너처는 exit 코드를 반환할 수 있는 능력도 있다. 그러나 자바와 마찬가지로, 반환 값을 갖지 않는 시작점을 갖는다는 것이 프로그램의 exit 코드가 설정될 수 없다는 것을 뜻하지는 않는다. 자바에서 프로그래머는 시스템을 빠져나가기 위한 값을 가지는 System.exit( int code)를 호출할 수 있다. C# 프로그래머는 System.Environment 클래스의 System.Environment 클래스의 ExitCode속성을 설정할 수 있으며 System.WinForms.Application.Exit()가 호출될 때, ExitCode의 값이 실행환경에 반환된다.
표준 출력, 에러, 입력
아마 대부분의 자바 프로그래머는 System.out, System.err, System.in 변수에 익숙할 것이다. 여기서 첫번째 두개의 변수는 java.io.PrintStreams인 반면, 세 번째 변수는 java.io.InputStream이다. 이러한 변수들은 명명된 스트림에 접근할 수 있다. 어떤 스트림에 있든지 상관없이, 다른 어떠한 스트림에 있고 데이터를 주고 받음으로 해서 이를 잘 다루는 것처럼 어떠한 프로그램도 이러한 스트림에 접근할 수 있다. 표준출력에 무언가를 쓰기 위해, 프로그램은 System.out 변수에 printIn을 호출한다. 표준 입력으로부터 데이터를 읽는 것은 read 메소드를 사용하거나 Hello.java에서 처럼, java.io.BufferedReader의 InputStream을 래핑하고 전체 라인을 읽음으로써 실행할 수 있다.
C#에서 표준입출력, 에러를 처리하는 방법이 똑같다. Out, Error, In으로 명명된 System.Console클래스에는 변수가 세 개 있다. Out과 Error는 둘 다 System.IO.TextWriters이며 이것은 Write와 WriteLine이라 명명된 메소드가 데이터를 보내는데 사용될 수 있다는 것을 의미한다. 반면에, In은 System.IO.TextReader이다. ReadLine 메소드는 한 줄의 문자를 읽기 위해 In에 사용된다. 위의 예제에 C#은 각각(예제에 사용된 메소드를 말한다) Out과 In으로부터 읽고 쓸 Write, WriteLine, Read, ReadLine이라 명명된 System.Console 안의 숏컷 메소드를 제공한다. 표준 에러를 쓰기 위한 숏컷은 없다.
예외
Hello 예제에서 자바와 C# 예외 사이에 별 차이가 없다고 생각할 수도 있다. 겉보기에는 그럴 수도 있다. 기본적인 차이는 C#에서의 모든 예외는 실행환경 예외(run-time exceptions)이며, 컴파일 시간 예외의 개념은 없다.
많은 프로그래머들은 좀더 빠른 프로토타입 환경을 제공하기 위한 하나의 시도로써 예외를 사용할 것이다. 그러나 강력한 애플리케이션을 작성할 때에는 예외를 사용할 때 매우 조심스러워야 한다. C# 컴파일러는 예외 조건을 고려하지 않으면 프로그래머에게 정보를 주지 않는다. 이미 나타난 예외는 메소드 시그너처에 목록이 나타나지 않기 때문에 프로그래머는 더 조심스러워야 한다. 이 때문에 모든 조건을 고려하고 있는지 확인하기 어려워진다.
소스 문서
자바 프로그래머는 JavaDoc 주석을 소스코드에 넣을 수 있으며, C# 프로그래머는 XML을 넣을 수도 있다. J2SE에서 "javadoc" 도구를 사용하면 생성된 문서의 결과를 안내해 줄 다른 doclet를 사용하는 방법을 알 수 있다. 디폴트에 의해, "javadoc"은 프레임이 익숙한 HTML을 생성한다. C#은 소스코드에서 문서를 포함하는 문법에 맞는 XML파일을 생성하기 위한 컴파일러를 사용할 수 있다.
Hello
a simple application that was ported from java to c#
the entry point into this class -- this class will
ask the user for his name, then reply to it
the command line arguments
0 if everything goes well, 1 if there is an error
|
일반적으로 이 다음에는 XSLT 변환을 통해 XML을 실행하여 HTML을 생성한다. 아니면 다른 문서를 살펴보는 것도 도움이 될 것이다.
컴파일과 실행
csc.exe 실행파일을 사용하면 Hello.cs을 컴파일 할 수 있다.
이것은 현재 실행 디렉토리내에서 3584바이트 크기의 Hello.exe 실행파일을 생성한다. Hello.exe는 마이크로소프트에서 제공하는 특정 DLL에만 의존하는 독립프로그램이다. 이 프로그램은 명령 프롬프트상태에서 "Hello"만을 입력하여 실행할 수 있다.
윈도우용 썬 마이크로시스템사의 JDK 1.3이 제공하는 Hello.classM파일이 1284바이트의 크기와 비교하면 Hello.exe는 많이 사이즈가 커진 듯하지만, 자바 프로그램이 20메가바이트의 자바 가상머신에서 실행되어야만 한다는 점을 생각하면 그렇지도 않다.
결론
자바와 C#의 개념과 문법은 대부분 비슷하지만, C#의 기본 사항을 익히고 나서라도 C#을 C# 자체로서 분석하기는 힘들 것이다. 이 글은 "자바 프로그래머를 위한 회화식 언어 C#"이라는 시리즈의 도입 부분이다. 공통 언어 실행환경이나, 닷넷에서 프로그램을 작성하고 싶다면, 시리즈의 나머지도 읽어 보기를 바란다.
Raffi Krikorian는 Cambridge.MA에서 컨설턴트 프리랜스로 활동하고 있으며 대형 분산 P2P 시스템, JXTA와 C#에 전문 컨설팅을 맡고있다
신동섭님은 한빛 리포터 1기로 활동 중이며, 전자공학을 전공했습니다. 현재 LG전자에 근무하고 있으며 네트워크 프로그램 개발을 담당하고 있습니다. 관심분야는 보안, 웹 솔루션, 프로토콜 등입니다.