C#과 Java언어 비교(11) - Attributes

C# and JAVA 2007. 5. 29. 11:26

http://genamics.com/developer/csharp_comparative_part10.htm


15.
어트리뷰트(Attributes)

C# Java 모두 컴파일된 코드 내에는 필드에 대한 접근수준과 같은 정보를 포함한다. C# 이러한 특성을 일반화하여 단순히 여러분이 클래스나 메소드, 필드 혹은 심지어 각각의 파라미터와 같은 요소들에 관하여 사용자가 직접 입력한 정보들도 컴파일할 있다. 이러한 정보들은 런타임시에 검색할 수도 있다. 아래에 어트리뷰터를 이용하는 클래스에 대한 매우 간단한 예제가 나와 있다:

[AuthorAttribute ("Ben Albahari")]
class A
{
    [Localizable(true)]
    public String Text {
        get {return text;
        }
        ...
    }
}

Java /** */ 주석을 결합하여 클래스와 메소드에 관한 추가정보들을 포함시키는데, 그러나 이러한 정보들은 바이트 코드에 내장되지 않는다. C# 미리 정의되어 있는 어트리뷰트인 ObsoleteAttribute 사용하여 컴파일러가 쓸모없는 코드(obsolete code) 대하여 경고할 있도록 하며, 그리고 ConditionalAttribute 사용하여 조건부 컴파일을 가능하게 수도 있다. 마이크로소프트의 새로운 XML 라이브러리는 어트리뷰트를 활용하여 필드가 XML 직렬화되는 방식을 표현하는데, 이는 여러분이 클래스를 쉽게 XML 변환한 다음 다시 그것을 재구성할 수도 있다는 것을 의미한다. 어트리뷰트를 사용하는 다른 적절한 예는 제대로 강력한 클래스 탐색도구를 만드는 것이다. C# 언어 레퍼런스는 어트리뷰트를 만들고 사용하는 방법에 관해 정확하게 기술하고 있다.

:

C#과 Java언어 비교(10) - Parameter Modifiers

C# and JAVA 2007. 5. 29. 11:23

http://genamics.com/developer/csharp_comparative_part9.htm


14.
파라미터 한정자(Parameter Modifiers)

 “ref” 파라미터 한정자

C#(Java와는 반대로) 여러분이 파라미터를 참조로 전달할 있도록 해준다. 이러한 점을 보여주는 가장 극명한 사례는 바로 일반목적용 swap 메소드이다. C++과는 달리 여러분은 ref 파라미터를 받는 메소드를 호출할 때는 물론 선언할 때에도 지정해 주어야만 한다:

public class Test
{
    public static void Main ()
    {
       int a = 1;
        int b = 2;
        swap (ref a, ref b);
    }
    public static void swap (ref int a, ref int b) {
       int temp = a;
       a = b;
       b = temp;
   }
}

 “out” 파라미터 한정자

 “out” 키워드라는 것도 있는데, 이것은 ref 파라미터 한정자 그대로 구현한 것이다. ref 한정자가 값이 메소드에 전달되기 전에 확실히 할당되어야 하는데 반해 out 한정자 리턴하기 전에 메소드의 구현이 확실히 파라미터에 값을 할당할 것을 필요로 한다.

“params” 파라미터 한정자

params 한정자 메소드의 가장 마지막 파라미터에 추가되어 메소드가 특정 타입의 임의 개수의 파라미터를 받아들일 있도록 한다. 예를 들자면 이런 것이다:

public class Test
{
    public static void Main () {
        Console.WriteLine (add (1, 2, 3, 4).ToString());
   }
    public static int add (params int[] array) {
       int sum = 0;
       foreach (int i in array)
           sum += i;
       return sum;
    }
}

여러분이 Java 배울 가장 놀라게 되는 중의 하나는 값을 참조로 전달할 없다는 점이다. 이것은 여러분이
조금 지나서 이러한 기능을 사용할 필요성을 별로 느끼지 못하고, 그러한 기능을 사용하지 않는 코드를 작성하기
때문이다. 필자가 C# 스펙을 처음으로 다루었을 종종 사람들이 이게 없으면 안된다고 할까? 나는 이것 없이도 코드를 작성할 있는데 말야라고 생각하곤 했다. 조금 자기반성해 보자면, 나는 이러한 별로 유용하지 않은 기능을 제공하는 것이 진정한 논쟁거리가 아니라 여러분이 그것 없이 코드를 작성해 나갈 있느냐가 논쟁거리임을 깨달았다.

여러분이 C++에서 했던 것을 생각해 보았을 Java 파라미터를 전달하는 방법을 간소화 것은 매우 잘한 일이다. C++에서 메소드의 파라미터와 메소드 호출은 값이나 참조, 추가적으로 포인터를 가지는 것들로 전달되는데, 이것은 불필요하게 복잡한 코드로 만들 있다. C# 메소드와 메소드 호출 모두 명시적으로 참조에 의해 전달될 있도록 하며 이는 혼동을 대폭 줄여주어 Java 목표와 동일한 목표를 달성할 있도록 해주는 반면 훨씬 풍부한 표현력을 제공해 준다. C# 테마는 프로그래머가 어떠한 일을 수행하는 있어 빙빙 돌아서 해결해야 하는 상황으로 치닫지 않게끔 하는데 있다. “참조에 의한 전달문제를 극복하는 것을 제시하는 Java 튜토리얼을 떠올려 보면 여러분은 1개의 요소를 가진 배열이 여러분의 값을 갖도록 전달해야 할까, 아니면 다른 클래스가 값을 갖도록 해야 할까?

:

C#과 Java언어 비교(9) - Versioning

C# and JAVA 2007. 5. 29. 11:11
13. 버전관리(Versioning)

버전관리 문제를 해결하는 것은 .NET 프레임워크의 주요 고려사항이었다. 이러한 고려사항의 대부분은 어셈블리(assemblies) 해당된다. 그러한 것들 중에는 동일한 프로세스에서 여러버전의 동일한 어셈블리들을 실행하는 것과 같은 강력한 특성이 가지 있다.

C# 언어는 새로운 버전의 코드(거의 대부분 닷넷 라이브러리) 만들어질 발생하는 소프트웨어 실패를 방지한다. C# 언어 레퍼런스에서 이것에 관해 자세하게 설명하고 있지만, 나는 그러한 문제를 하나의 상당히 함축한 예로 요약해 보겠다.

Java에서 JVM 함께 배포된 B클래스를 파생하는(derive) D라는 클래스를 배포한다고 가정해 보자. D 클래스는 foo라는 메소드를 하나 갖고 있는데, B 배포될 당시에는 B에는 메소드가 포함되어 있지 않았다. 나중에 B 업데이트되어 이제는 B 클래스에 foo라는 메소드를 포함하게 되었으며, D 클래스를 이용하는 소프트웨어를 실행하는 컴퓨터에 VM 설치되었다. D 클래스를 이용하는 소프트웨어는 오작동을 일으킬지도 모르는데, 왜냐하면 B 클래스의 새로운 구현체는 D 클래스에 대하여 가상 호출(virtual call) 하여 B 클래스에서는 전적으로 의도하지 않은 구현에 대한 행위를 수행할 것이기 때문이다. C#에서는 D클래스의 foo 메소드는 override 한정자(프로그래머의 의도를 표현하여) 없이 선언될 수도 있었기 때문에, 런타임은 D 클래스의 foo 메소드가 B 클래스의 foo 메소드를 재정의하지 않고 숨겨야 함을 알게 된다.

C# 레퍼런스 문서로부터 한가지 흥미로운 것을 인용해본다: “C# 이러한 버전관리 문제를 개발자들로 하여금 그들의 의도 명확히 하게하여 해결한다”. 비록 override 키워드를 사용하는 것이 의도를 나타내는 가지 방법이긴 하지만 메소드가 컴파일 시점에 재정의를 수행하는지를(선언하기 보다는) 확인함으로써 컴파일러에 의해 자동적으로 생성되도록 수도 있다. 이는 여러분이 여전히 Java스러운 언어(virtual override 키워드를 사용하지 않는) 가지고도 버전관리 문제를 적절히 해결할 있음을 의미한다.

필드 한정자(Field Modifiers) 살펴보아라.

:

C#과 Java언어 비교(8) - Interfaces

C# and JAVA 2007. 5. 29. 11:06

http://genamics.com/developer/csharp_comparative_part8.htm


12.
인터페이스(Interfaces)

C# 인터페이스는 Java 인터페이스와 유사하지만 높은 유연성을 갖고 사용될 있다.
어떠한 클래스도 명시적으로인터페이스를 구현할 있다:

public interface ITeller
{
    void Next ();
}
 
public interface IIterator
{
   void Next ();
}
 
public class Clark : ITeller, IIterator
{
    void ITeller.Next () {
    }
    void IIterator.Next () {
    }
}

위에서 주어진 클래스는 가지 이점을 갖는다. 첫째는 하나의 클래스가 이름 충돌(naming conflicts)
걱정하지 않고도 여러 인터페이스를 구현할 있다는 것이다. 두번째는 클래스가 클래스의 일반 사용자에게
유용하지 않을 경우 메소드를 숨기도록해준다. 명시적으로 구현된 메소드는 필요한 인터페이스로
클래스 형변환을 통해 호출될 있다.

Clark clark = new Clark ();
((ITeller)clark).Next();
:

C#과 Java언어 비교(7) - Polymorphism

C# and JAVA 2007. 5. 29. 11:05

http://genamics.com/developer/csharp_comparative_part8.htm


11. 다형성(Ploymorphism)

가상 메소드(virtual method)는 객체지향 언어가 다형성을 표현할 수 있도록 해준다. 이것은 파생 클래스가 기반 클래스에 있는 메소드와 동일한 시그너처를 가진 메소드를 작성할 수 있으며, 기반 클래스에서 파생 클래스의 메소드를 호출할 수 있다는 것을 의미한다. 기본적으로 Java에서는 모든 메소드가 가상이다. C#에서는 C++에서와 같이 virtual 키워드를 사용하여야만 메소드를 기반 클래스에서 호출될 것이다.

C#에는 그뿐만 아니라 기반 클래스의 메소드를 재정의해야할(혹은 추상 메소드를 구현해야 하는) 메소드에는 override 키워드를 지정할 필요가 있다

Class B {
    public virtual void foo () {}
}

Class D : B {
    public override void foo () {}
}

메소드가 의도적으로 기반 클래스의 메소드를 숨김을 의미하는 “new” 키워드를 선언에 추가하지 않은채로 비가상 메소드를 재정의하려고 하게 되면 컴파일 타임 에러가 발생하게 될 것이다.
Class N : D {
    public new void foo () {}
}

N n = new N ();
n.foo(); // calls N's foo
((D)n).foo(); // calls D's foo
((B)n).foo(); // calls D's foo

C++과 Java에서와는 대조적으로 override 키워드를 필요로 하는 것은 소스코드를 볼 경우 어떤 메소드가 재정의 되었는지 좀 더 명확하게 알 수 있도록 해준다. 그러나 가상 메소드를 사용하는 것에는 나름 장점과 단점이 있다. 가상 메소드를 사용하는 것의 첫번째 장점은 가상 메소드를 명시하지 않는 것 보다 수행 속도가 조금 더 향상된다는 점이다. 두 번째 장점은 어떤 메소드가 재정의될지가 명확해 진다는 점이다. 그러나 이러한 장점이 곧 단점이 될 수 있다. 기본 옵션으로 Java에서 final 한정자를 두는 것과 C++에서 virtual 한정자를 두는 것을 비교해 보자. Java에서의 기본 옵션은 여러분의 프로그램이 다소 비효율적으로 실행되게끔 할 수도 있으며, 반면에 C++에서는 비록 예상치 못한 일일지라도 기반 클래스의 구현으로 인해 확장성이 제한될 수 있다.
:

C#과 Java언어 비교(6) - Operator Overloading

C# and JAVA 2007. 5. 29. 10:57

http://genamics.com/developer/csharp_comparative_part7.htm


10.
연산자 오버로딩(Operator Overloading)

연산자 오버로딩은 프로그래머가 자연스럽게 받아들일 있는 타입을 만들어 그것을 단순한 타입(int, long )처럼 사용할 있도록 해준다. C# C++ 보다는 엄격한 버전의 연산자 오버로딩을 구현하긴 하지만 연산자 오버로딩의 전형적인 예와 같은 클래스와 복잡한 숫자 클래스도 작동하도록 해준다.

C#에서 == 연산자는 레퍼런스로 비교되는 object 클래스의 비가상(non-virtual; 연산자는 virtual 없다) 메소드이다. 여러분이 클래스를 만들 여러분만의 == 연산자를 정의할 수도 있다. 만약 여러분이 컬렉션을 가진 클래스를 사용할 경우에는 IComparable 인터페이스를 구현해야만 한다. 인터페이스는 개의 구현해야할 메소드를 가지고 있는데, CompareTo(object) 메소드로 불리며 “this” 크면 양수를, 작으면 음수를, 혹은 객체와 같은 값을 가질 경우 0 리턴해야 한다. 또한 여러분이 만든 클래스를 사용하는 사람이 나은 문법을 갖기를 원한다면 <, <=, >=, > 메소드를 정의할 수도 있다. 수치형 타입(int, long ) IComparable 인터페이스를 구현한다.

아래에는 동일성과 비교를 처리하는 방법의 예를 보여준다:

public class Score : IComparable
{
    int value;
    public Score (int score) {
        value = score;
    }
 
    public static bool operator == (Score x, Score y) {
        return x.value == y.value;
    }
 
    public static bool operator != (Score x, Score y) {
        return x.value != y.value;
    }
 
    public int CompareTo (object o) {
        return value - ((Score)o).value;
    }
}
 
Score a = new Score (5);
Score b = new Score (5);
Object c = a;
Object d = b;








a
b 레퍼런스로 비교하려면:
System.Console.WriteLine ((object)a == (object)b; // false 

a
b 값으로 비교하려면:
System.Console.WriteLine (a == b); // true

c
d 레퍼런스로 비교하려면:
System.Console.WriteLine (c == d); // false

c
d 값으로 비교하려면:
System.Console.WriteLine (((IComparable)c).CompareTo (d) == 0); // true

또한
여러분은 <, <=, >=, > 연산자를 추가하여 클래스의 점수를 매길 수도 있다. C# 논리적으로 짝을 이루는
(!= ==, > <, >= <=) 연산자가 모두 정의되어야 함을 컴파일 시점에서 보장한다.
:

C#과 Java언어 비교(5) - Structs, Type Unification

C# and JAVA 2007. 5. 29. 10:55

http://genamics.com/developer/csharp_comparative_part6.htm


8.
구조체


 
단지 여러분이 필요하기 때문에 정말로 효율적인 코드를 작성하기 위한 한가지 방법으로만이 아닌 C# 타입체계가 우아하게 돌아가게 만들어주는 구성요소의 하나로서 C# 구조체를 살펴보는 것도 유익한 일이다.


C++
에서는 구조체와 클래스(객체) 둘다 스택/인라인 혹은 힙에 할당될 있다. C#에서는 구조체는 항상 스택/인라인 영역에 생성되며 클래스(객체) 항상 힙에 생성된다. 구조체는 실제로 효율적인 코드를 작성할 있도록 해준다:


public struct Vector {

    public float direction;

    public int magnitude;

}

 

Vector[] vectors = new Vector [1000];


코드는 1000개의 벡터(Vector) 모두 곳에 집어넣을 공간을 할당할 것이며, 우리가 벡터를 하나의 클래스로 선언하고 for 반복문을 이용하여 1000개의 벡터를 인스턴스화하였으므로 훨씬 효율적이다. 우리가 효율적으로 해낸 부분은 우리가 C#s이나 Java에서 수형 배열(int array) 선언하는 것과 비슷하게 선언된 배열이다:


int[] ints = new ints [1000];


C# 여러분이 언어에 내장되어 있는 원형 타입(primitive)들을 간단하게 확장할 있도록 해준다. 사실 C# 모든 원형타입을 구조체로서 구현한다. int 타입은 단순히 System.Int32 구조체의 별칭일 뿐이며 long 타입은 System.Int64 구조체 등의 별칭일 뿐이다. 이러한 원형타입들은 당연히 컴파일러에서 특별하게 처리될 수도 있지만 언어 자체는 그러한 구분을 짓지는 않는다. 다음 섹션은 C# 이러한 것들을 어떻게 이용하는지 보여줄 것이다.

 


9.
타입 단일화(Type Unification)


대부분의
언어는 원형타입(int, long ) 궁극적으로는 원형 타입들로 이루어진 고수준의 타입들을 가지고 있다. 그것은 종종 원형타입과 고수준 타입들을 동일한 방식으로 다룰 있기 때문에 유용하다. 예를 들어 정수 뿐만 아니라 문자열 모두를 가질 있는 컬렉션을 갖는 것이 유용할 때가 있다. 스몰토크(smalltalk) 어느정도의 효율성을 희생하고 int long String이나 Form으로 다루게 함으로써 이것을 가능하게 하고 있다. Java 이러한 효율성을 희생하는 것을 피하여 C C++에서와 같이 원형타입을 다루지만 각각의 원형 타입에 대응되는-int Integer, double Double- 래퍼(Wrapper) 클래스를 제공하고 있다. C++ 템플릿(template) 타입에 대한 연산을 타입에서 제공하는 어떠한 타입도 받아들이도록 작성된 코드를 있도록 해준다.


C#
이러한 문제에 대하여 색다른 해결책을 제공한다. 이전 섹션에서 필자는 어떻게 int 같은 원형 타입이 단순히 구조체에 대한 별칭일 뿐이었는지를 설명하면서 C# 구조체를 소개하였다. 이는 구조체가 object 클래스가 가진 모든 메소드를 갖기 때문에 다음과 같은 코드를 있도록 해준다:


int i = 5;

System.Console.WriteLine (i.ToString());



만약
구조체를 객체로 사용하고 싶을 경우, C# 구조체를 객체로 박싱할 것이며 다시 그것을 구조체로 사용하고 싶을 때에는 언박싱해줄 것이다.


Stack stack = new Stack ();

stack.Push (i); // box the int

int j = (int) stack.Pop(); // unbox the int



구조체를
언박싱할 필요한 형변환과는 상관없이 이는 여러분이 구조체와 클래스간의 관계를 일관성 있게 처리하는 방법이다. 여러분은 비록 CLR 박싱된 객체에 대한 별도의 최적화를 제공해 줄지는 몰라도 박싱이 래퍼 객체를 양산하는 것을 수반한다는 것을 털어놓아야 것이다.


C#
설계자들은 설계 과정동안 템플릿을 고려해야만 했다. 필자는 템플릿을 사용하지 않은 이유에 대해 두가지 주요 원인이 있었으리라  짐작하는데, 첫번째는 설계가 난잡해 있다는 점이다. 템플릿은 어려워서 객체지향적인 특성들을 뒤죽박죽 섞어놓을 있고, 템플릿은 프로그래머에게 너무 많은(혼란스러울 정도로) 설계 가능성을 열어주며, 리플렉션(reflection) 결합하기가 어렵다. 번째 이유는 컬렉션과 같은 닷넷 라이브러리가 템플릿을 사용하지 않을 경우 템플릿은 그렇게까지 유용하지는 않을 것이라는 점이다. 그러나 만약 닷넷 클래스에서 템플릿을 사용했다면 닷넷 클래스들을 사용하는 20개 이상의 언어들도 템플릿도 결합해야만 했을 것이며, 이를 기술적으로 이뤄내기가 상당히 어려웠을지도 모른다.


템플릿
(제네릭) Java Community Process 의해 Java 언어에 포함할 것을 고려중이라는 것도 흥미로운 일이다. 그렇게 되면 기업은 Sun에서 닷넷은 최소 공분모 신드롬(lowest common denominator syndrome) 겪고 있다라고 말하고 Microsoft “Java 교차 언어(cross-language support) 지원하지 않는다라고 말할 때부터 서로의 곡조에 맞춰 노래를 부르기 시작한지도 모르겠다.


 
(8
10 수정) Anders Hejlsberg 인터뷰를 읽은 후로 위에서 제시했던 어려움 때문에 번째 릴리즈는 아니지만 템플릿이 나타날 것이 임박해졌다. 바이트 코드(byte-code) 아니지만 중간언어(IL) 스펙이 IL 코드가 템플릿을 표현(리플렉션과 어울릴 있도록 비파괴적인(non-destructive) 방법으로) 있도록 작성되어 졌음을 살펴보는 것도 매우 재미있었다. Java 제네릭을 도입하려고 고려중인 Java Community Process 관한 링크도 첨부한다:

:

C#과 Java언어 비교(4) - Enums, Foreach문

C# and JAVA 2007. 5. 29. 10:52

http://genamics.com/developer/csharp_comparative_part5.htm

6. 열거형(Enums)

여러분이 C 언어를 모를 경우를 생각해서 설명하는 거지만 Enums 여러분이 객체의 집합을 지정할 있도록 해주는데, 예를 들어:


선언:

public enum Direction {North, East, West, South};


사용법:

Direction wall = Direction.North;


열거자는 쓸만한 구성요소(construct)이므로 혹시나 여러분은 C# 그것들을 포함하기로 결정하지 않았는지에 대한 의문이 들지도 모르겠지만 그럼 Java 그것들을 생략하기로 결정했을까? Java 경우, 여러분은 다음과 같이 해야만 한다.


선언
:

public class Direction {

        public final static int NORTH = 1;

        public final static int EAST = 2;

        public final static int WEST = 3;

        public final static int SOUTH = 4;

}


사용법:

int wall = Direction.NORTH;


Java
버전이 많은 것들을 표현해 주는 것처럼 보이는 것이 사실임에도 불구하고 그것은 조금 안정적(type-safe)이지 못한데, 왜냐하면 여러분이 뜻하지 않게 컴파일러가 잡아내지도 않게 하면서 wall 아무 정수값에 할당할 있도록 해주기 때문이다. 정확하게 하기 위해서 Java 대한 필자의 경험으로는 가지 추가적인 토큰을 작성하고 여기에서 나타나 있는 -안전성이 결핍되어 나타나는 오류를 찾아내는 그렇게 많은 시간이 들지는 않았었음에도 불구하고 열거자가 있는 것이 좋다. C# 가지 이점은 여러분이 디버깅하기가 놀랄만큼 좋다는 것인데, 만약 여러분이 열거형들이 결합되어 있는 것을 가진 열거형(enumeration) 중단점(break point) 경우 C# 여러분이 해독해야만 하는 숫자 대신 자동적으로 direction 해독하여 사람이 판독할 있는 출력결과를 여러분에게 보여준다:


선언:

public enum Direction {North=1, East=2, West=4, South=8};

 

사용:

Direction direction = Direction.North | Direction.West;

if ((direction & Direction.North) != 0)

    ....


만약
여러분이 if 문에 중단점을 걸게 되면 여러분은 숫자 5 아닌 사람이 읽을 있는 버전의 direction 보게 것이다.

Java에서 열거형이 없는 가장 그럴듯한 이유는 여러분이 열거형 대신 클래스를 이용하여 그럭저럭 해낼 있기 때문이다. 이전 섹션에서 필자가 언급했던 것처럼 단독적인 클래스를 갖고서는 세상의 특징을 표현하는 것은 물론이거니와 다른 구성요소와 함께 있는 역시 불가능하다. 클래스로 있는 것이면 새로운 구성요소를 도입하지 마라라는 Java 철학이 가져다 주는 이점은 뭘까? 단순성(simplicity) 아마도 가장 이점으로 보여지는데, 이는 짧은 학습곡선과 프로그래머로 하여금 어떤 일들을 하는 있어 여러가지 방식으로 생각해야만 하는 것을 방지해 준다. 사실 Java 언어는 포인터와 헤더 파일을 제거하고, 단일한 객체 상속(single-rooted object hierarchy) 같은 단순함을 목적으로 여러가지 면에서 C++ 개선하여 만들어졌다. 그러나 이러한 모든 간소화(simplifications) 공통적인 측면은 Java 실질적으로 코드 작성을 더욱 단순하게 만들어준다는 점이다. 다른 구성요소들을 제외하고 우리는 지금까지 열거자, 프로퍼티, 그리고 이벤트에 대해 살펴보았는데, 이것들은 여러분의 코딩을 복잡하게 만든다.

 

7. 컬렉션과 Foreach

C# for 반복문의 짧은 형태를 제공하는데, 이것도 역시 컬렉션 클래스에 대한 일관성을 증가시키도록 도와준다.

Java C++ 경우:

1. while (! collection.isEmpty()) {

        Object o = collection.get();

        collection.next();

        ...

2. for (int i = 0; i < array.length; i++)...


C#
에서는:

1. foreach (object o in collection)...

2. foreach (int i in array)...


C#
for 반복문은 컬렉션 객체(컬렉션을 구현하는 배열)에서만 효과가 있을 것이다. 컬렉션 객체는 열거형 객체(Enumerator object) 리턴하는 GetEnumerator() 메소드를 갖고 있다. 열거형 객체는 MoveNext 메소드와 Current 프로퍼티를 갖는다.

 
// 내용이 꽤 됐네요... Java에서는 열거형과 enhanced for loop라고 해서 C#의 foreach 반복문과 같은 역할을 하는 문법이 1.5부터 추가되었죠.

:

C#과 Java언어 비교(3) - Event

C# and JAVA 2007. 5. 29. 10:49

원문 : http://genamics.com/developer/csharp_comparative_part4.htm

5. 이벤트

C# 직접적으로 이벤트를 지원한다. 비록 이벤트 처리가 프로그래밍이 시작된 이래로 프로그래밍에서 필수적인 부분이었다고는 하지만 대부분의 언어에서 이벤트의 개념을 정형화하고자 하는 노력은 놀랍게도 거의 없었다. 만약 여러분이 오늘날의 주류를 차지하는 프레임워크에서 이벤트를 처리하는 방식을 살펴보게 된다면 델파이(Delphi) 함수 포인터(클로져(closure) 불리는) Java 내부 클래스 어댑터, 그리고 물론 Windows API 메시지 시스템과 같은 선례를 찾을 있을 것이다. C# event 키워드와 함께 대리자(delegates) 이용하여 이벤트 처리에 있어 매우 깔끔한 해결책을 제시한다. 필자는 이를 보여주는 최선의 방법은 이벤트를 선언하고, 일으키고(fire), 처리하는 전체 과정을 보여주는 예제를 보여주는 것이라 생각한다:

// 호출될 있는 메소드의 서명을 정의하는 위임 선언

public delegate void ScoreChangeEventHandler (int newScore, ref bool cancel);

 

// 이벤트를 만드는 클래스

public class Game {

    // event 키워드를 사용하였음을 주목

    public event ScoreChangeEventHandler ScoreChange;

 

    int score;

 

        // Score 프로퍼티

    public int Score {

        get {

            return score;

            }

        set {

            if (score != value) {

                bool cancel = false;

                ScoreChange (value, ref cancel);

                if (! cancel)

                    score = value;

            }

        }

    }

}

 

// 이벤트를 처리하는 클래스

public class Referee

{

    public Referee (Game game) {

        // 게임에서 점수가 언제 변하는 지를 관찰함

        game.ScoreChange += new ScoreChangeEventHandler (game_ScoreChange);

    }

 

    // 메소드의 서명이 ScoreChangeEventHandler 서명과 어떻게 일치하는지 주목하라

    private void game_ScoreChange (int newScore, ref bool cancel) {

        if (newScore < 100)

            System.Console.WriteLine ("Good Score");

        else {

            cancel = true;

            System.Console.WriteLine ("No Score can be that high!");

        }

    }

}

 

// 모든 것들을 테스트 하는 클래스

public class GameTest

{

    public static void Main () {

        Game game = new Game ();

        Referee referee = new Referee (game);

        game.Score = 70;

        game.Score = 110;

    }

}

GameTest에서는 게임을 하나 만들고, 게임을 관찰하는 참조변수를 하나 만든 다음, 참조 대상이 게임 점수가 변경되었을 어떻게 반응하는지를 확인해 보기 위하여 게임 점수를 변경한다. 시스템에서 Game 참조변수에 대해 아무것도 알지 못하며, 그리고 아무 클래스나 점수가 변경되는 것을 감시하고 변화에 대응하도록 해준다. event 키워드는 모든 대리자의 메소드를 += -=과는 상관없이 그것이 선언되어 있는 클래스가 아닌 클래스로 숨긴다. 이러한 연산자는 여러분이 원하는 만큼 여러 개의 이벤트 처리기를 이벤트에 추가하거나 제거할 있도록 해준다.


여러분은
아마도 GUI 프레임워크에서 이러한 시스템을 처음 접하게 될텐데, Game 사용자 입력에 따라 이벤트를 일으키는 UI 위젯에 해당되며, 참조 대상은 이벤트를 처리하게 폼에 해당될 것이다.


대리자는
Microsoft J++에서 처음으로 도입되었으며, 또한 Anders Hejlsberg 의해 설계되었고 Sun Microsoft간의 수많은 기술적, 법적 분쟁을 야기시켰다. Java 설계했던 James Gosling Anders Hejlsberg 관해 그의 델파이에 대한 애착이 그를 메소드 포인터씨(Mr. Method Pointers)” 만들었다라고 말하면서 농담을 건넸다. Sun에서 만들어진 대리자에 관한 논쟁을 검토한 후로 필자는 Gosling “’모든 것은 클래스다 부르는 것이 공평하다고 생각한다. 지난 년간의 프로그래밍은 현실을 모델링하기 위해 추상화하는 으로부터 많은 사람들에 의해 현실은 객체지향이며, 따라서 우리는 객체지향적인 추상화를 통해 모델링해야만 한다 바뀌었다.

대리자에 관한 Sun Microsoft 논쟁은 아래에서 찾아볼 있다:

:

C#과 Java언어 비교(2) - Indexers, Delegates

C# and JAVA 2007. 5. 29. 10:30

http://genamics.com/developer/csharp_comparative_part3.htm


3.
인덱서(Indexers)

C# 프로퍼티에서 했던 것 처럼 각각의 요소를 get 그리고/혹은 set 메소드를 통해 외부로 노출하는 것을 제외하고 객체를 배열처럼 다룰 있도록 해주는 인덱서(indexers) 제공한다.

public class Skyscraper
{
Story[] stories;
public Story this [int index] {
get {
return stories [index];
}
set {
if (value != null) {
stories [index] = value;
}
}
}
...
}
Skyscraper empireState = new Skyscraper (...);
empireState [102] = new Story ("The Top One", ...);


4.
대리자(Delegates)

대리자는 타입에 안전한(type-safe) 객체지향 함수 포인터로 생각할 있는데, 개의 메소드가 아니라 여러 개의 메소드를 가질(hold) 있는 것을 말한다. 대리자는 C++에서 함수 포인터를, Java에서는 인터페이스를 이용하여 해결할 있는 문제를 다룬다. 대리자는 형식에 안전하며, 그리고 여러 메소드를 가질 있으므로 함수 포인터를 보다 좋게 만든다. 대리자는 내부 클래스 어댑터(inner-class adapter) 여러 메소드 호출을 처리하는 별도의 코드 없이도 메소드에 대한 호출을 있도록 해줌으로써 인터페이스적인 접근법을 보다 좋게 한다. 대리자의 가장 중요한 쓰임은 이벤트 처리인데, 이는 다음 섹션(어떻게 대리자를 이용하는지에 대한 예제를 보여줄 것이다)에서 다룰 것이다.

// 오전에 급.. List로 작성한 코드가 있었는데... 아무리 찾아봐도 Java에서 흔히 이용하던 GetXXX류의 메소드가 없어서 황당했었는데, 결국 인덱서로 접근하는 것이었어!!! -_-;;

: