소프트웨어/C# & ASP.NET

C# 4.0의 새로운 기능

falconer 2009. 12. 15. 20:38

Written by 안재우(Jaewoo Ahn), 닷넷엑스퍼트(.netXpert)

 

이미 많은 분들이 알고 계시겠지만, 드디어 C#의 버전이 4.0이 되었습니다. Microsoft의 버전 업그레이드질(?)에 지치셨을 분들에게 큰 압박이 되겠군요. -.-; 우선 4.0을 돌아보기 전에 그 과거부터 돌아봅시다.

 

C# 1.0

C# 1.0은 .NET 1.0 및 Visual Studio 2002와 함께 출시되었습니다. 한참 다른 언어(예: Java, C++)와 C#을 비교하는 얘기들이 많던 시절이었죠. 일부 사람들에게는 C계열 언어의 사생아(?)라는 혹평을 듣기도 했으나, 컴파일러/프로그래밍 언어의 귀재인 Anders Hajelsburg의 존재를 무시할 수는 없었을 겁니다.

 

2002년~2003년 지음, Anders Hajelsburg는 C# 언어가 추구하는 방향을 'Most Modernized Programming Language'라는 개념으로 간단하게 정리했습니다. 말 그대로 현대에 나오는 프로그래밍 언어에 대한 개념 중 바람직한 것이 있다면 어느 언어보다도 빨리 적극적으로 흡수하는 프로그래밍 언어가 될 것이다라는 뜻입니다. (이 때부터 고생문이 훤하겠다 싶었습니다.)

 

추억을 돌아보고 싶으신 분들은 MSDN에서 다음 페이지를 보시죠. 이 시절에는 C# 언어 사양을 온라인 버전으로도 볼 수 있었습니다.

Visual C# Language (C#) - 영문

Visual C# 언어(C#) - 한글

 

C# 2.0

C# 2.0은 .NET 2.0 및 Visual Studio 2005와 함께 출시되었습니다. C# 1.0 시절까지만 해도 프로그래밍 언어와 개발도구의 경계가 좀 애매하던 시절이었긴 하지만, 2.0에 와서야 언어와 개발도구를 명시적으로 분리를 하기 시작했습니다.

 

C# 2.0에서 새로운 기능들은 다음 항목에 잘 정리되어 있습니다.

What's New in the C# 2.0 Language and Compiler - 영문

C# 2.0 언어 및 컴파일러의 새로운 기능 - 한글

 

제 블로그에서도 C# 2.0에 대한 내용을 소개한 적이 있습니다.

C# 2.0 및 VB.NET 2005의 새로운 기능 1 - Generic

C# 2.0 및 VB.NET 2005의 새로운 기능 2

C# 2.0 및 VB.NET 2005의 새로운 기능 3

 

여러가지 변화가 있긴 하지만, C# 2.0에서의 가장 핵심적인 변화사항은 역시 Generic과 Partial Type이라고 봅니다. 이 두 가지로 인해 이후 C# 언어, 개발도구, 프레임워크 라이브러리 등에 많은 변화가 일어나게 되니까요. 아, 물론 Nullable TypeIterator,  Anonymous 메서드, Static 클래스Friend 어셈블리 등도 중요합니다.

 

C# 3.0

C# 3.0은 .NET 3.5 및 Visual Studio 2008과 함께 출시되었습니다. 무엇보다 C# 3.0에서의 가장 큰 변화는 PDC에서 소개되었던 LINQ의 도입과 var 키워드의 지원입니다. 물론 그 외에도 많은 변화가 있었습니다. 자세한 건 다음 내용을 읽어보시기 바랍니다.

What's New in Visual C# - 영문

Visual C#의 새로운 기능 - 한글

 

LINQ나 var 키워드 외에 나머지 항목들이 흥미로운 것은 완전히 새롭게 등장한 개념이라기 보다는 기존 C#에서의 연장 선상을 보여주는 항목들이 많습니다. 또한 미래를 예측해볼 수도 있죠. ^^

 

예를 들어, partial type (C# 2.0)에 이어 partial method가 등장했습니다. 현재 C# 4.0에는 포함되어 있지 않지만, 언젠가는 partial property도 등장하지 않을까 추측이 됩니다. (저 뿐만 아니라 여러 C# MVP들이 요청하는 기능 중 하나이죠)

delegate -> anonymous method -> lambda expression으로의 발전 역시 흥미로운 항목입니다. 친절하게도 MSDN에서는 다음 예제를 통해 C# 1.0에서 C# 3.0까지의 대리자(delegate) 발전 과정을 한 눈에 보여줍니다. ^^

 

class Test
{
    delegate void TestDelegate(string s);
    static void M(string s)
    {
        Console.WriteLine(s);
    }

    static void Main(string[] args)
    {
        // Original delegate syntax required 
        // initialization with a named method.
        TestDelegate testdelA = new TestDelegate(M);

        // C# 2.0: A delegate can be initialized with
        // inline code, called an "anonymous method." This
        // method takes a string as an input parameter.
        TestDelegate testDelB = delegate(string s) { Console.WriteLine(s); };

        // C# 3.0. A delegate can be initialized with
        // a lambda expression. The lambda also takes a string
        // as an input parameter (x). The type of x is inferred by the compiler.
        TestDelegate testDelC = (x) => { Console.WriteLine(x); };

        // Invoke the delegates.
        testdelA("Hello. My name is M and I write lines.");
        testDelB("That's nothing. I'm anonymous and ");
        testDelC("I'm a famous author.");

        // Keep console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    } 
}
/* Output:
    Hello. My name is M and I write lines.
    That's nothing. I'm anonymous and
    I'm a famous author.
    Press any key to exit.
*/

static 멤버 -> static 클래스 -> extension(확장) 메서드 역시도 그 연장 선상에 있습니다. 특히 프레임워크 라이브러리나 유틸리티 작업을 많이 하는 사람들에게 extension 메서드는 이제 거의 필수입니다.

 

C# 4.0

도대체 C# 4.0은 언제할건데? 자, 이제 시작합니다. -.-;;

사실 이제와서 하는 얘기입니다만, 이 포스트를 쓸까 말까를 무척이나 망설였습니다. 왜냐하면, 사실 굳이 쓰지 않더라도 C# 언어 PM인 Mads Torgersen이 쓴 New Features in C# 4.0에 너무나 잘 정리되어 있기 때문입니다. 그러나, 영어에 약하신 분들을 위해 간단하게 정리해보도록 하겠습니다. ^^

 

C# 4.0은 .NET 4.0 및 Visual Studio 2010과 함께 출시될 예정입니다. C# 4.0의 주요 테마는 이미 Dynamic in C# 4.0 포스트에서 소개했다시피 바로 dynamic입니다. 역시 얘기되었던 대로 C#은 여전히 static type 언어입니다만, dynamic type들과 상호 작용을 할 수 있는 기능들이 추가됩니다.

사실 C# 4.0에서 dynamic 외에 Visual Basic과의 co-evolution이라는 테마를 가지고 있긴 한데, Microsoft 내부적으로는 의미가 있겠지만 외부적으로는 별 의미가 없는 것 같습니다. VB 사용자 분들에게는 죄송하지만, 최근 몇 년간 VB는 C#의 발전을 기를 쓰고 따라 잡기에 급급한 모습인 듯 합니다. 사실 C# 입장에서는 말이 co-evolution이지, '님하 살살 좀'을 외치는 VB도 따라 와 줄 수 있기에 '당분간 천천히 가줄께'라는 것 같거든요.

 

New Features in C# 4.0에서는 C# 4.0의 새 기능들을 크게 4개 덩어리로 나누고 있습니다.

- Dynamic lookup

- Named and optional parameters

- COM specific interop features

- Variance

 

Dynamic lookup

Dynamic lookup에 대해서는 이미 Dynamic in C# 4.0에서 기본적인 내용을 소개했으니, 따로 설명하지 않겠습니다. 하지만 자세한 내용을 원하시는 분들은 New Features in C# 4.0에서 해당 부분을 반드시 읽어보시기 바랍니다. 특히 Open issues 절에서는 C# 4.0에서 dynamic과 관련한 제한사항들을 다루고 있습니다. DLR 관련 내용은 제쳐두더라도 extension 메서드를 사용할 수 없다거나, anonymous 함수를 메서드 호출 인수로 사용할 수 없어 LINQ 쿼리의 사용이 제한된다는 내용들은 주의할 항목입니다. 아쉽게도 이 제한사항들은 C# 4.0에서는 개선될 계획이 없습니다.

 

Named and optional parameters

이건 예제를 드는 것이 가장 설명이 쉬울 듯 합니다. 예를 들어, 다음과 같은 메서드가 있다고 가정합시다.

 

public void M(int x, bool option1, string option2);

 

그런데, 대부분 x 값만 넘겨주고, option1과 option2는 정해진 값만 넘기는 경우가 많다고 가정합시다.

 

M(100, false, null);

 

사실 이 경우, 다음과 같은 게 있으면 편할 겁니다.

 

M(100); // option1 = false, option2 = null;

 

하지만 현재는 이를 하기 우해서는 M 메서드를 일일이 다 오버로딩하는 수 밖에 없죠.

 

public void M(int x) { M(x, false, null); }

 

C# 4.0에서는 Optional Parameter가 도입되어 다음과 같이 처리가 가능합니다.

 

public void M(int x, bool option1 = false, string option2 = null);

 

이제 M 메서드는 다음과 같은 3가지 모두로 호출이 가능합니다.

 

M(100, false, "Hello")

M(100); // option1 = false, option2 = null;

M(100, true); // option 2 = null;

 

그런데 만약 중간에 있는 option1만 생략하고 싶다면 어떻게 해야 할까요?

전통적인 방법이라면 다음과 같이 될 것입니다.

 

M(100, , "Hello");

 

하지만 C# 팀은 이 경우 가독성이 저하된다고 판단하고, named parameter라는 개념을 도입했습니다.

M(1, option2: "Hello");

 

named parameter를 쓸 경우, 메서드 인수의 순서를 바꿀 수도 있습니다.

 

M(option2: "Hello", x: 100);

 

COM specific interop features

Dynamic과 named/optional parameter 덕에 COM API를 사용하는 것이 좀 더 편리해졌습니다. 그리고 COM에 국한된 몇 가지 interop 관련 기능이 추가되었습니다.

 

먼저 COM에서는 Variant 타입을 쓰는 경우가 많은데, Variant의 경우 PIA(Primary Interop Assembly)에서는 object로 표현됩니다. 따라서 항상 object 타입을 자신이 사용하려는 타입으로 변환해야 하는 경우가 많았습니다. C# 4.0에서는 object 대신 dynamic을 사용해서 variant를 표현하는 것이 가능합니다. 예를 들자면 다음과 같죠.

 

((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello";  // 기존 방식(cast 필요)

excel.Cells[1, 1].Value2 = "Hello";  // C# 4.0(cast 필요없음)

 

Optional Parameter의 지원으로, Default Parameter 등의 처리도 쉬워졌습니다. Missing.Value 노가다를 해보신 분들은 무슨 의미인지 이해하실 듯.. ^^

 

excel.Workbooks.Add(Missing.Value); // 기존 방식

excel.Workbooks.Add(); // C# 4.0

 

또한 no-PIA라는 기능이 생겼습니다. 예전에는 COM 인터페이스를 strong type으로 interop하기 위해서는 PIA 어셈블리가 필요했는데, 덩치도 크다는 것도 있고 PIA는 별도로 배포되는 것이라 버전 관련 문제가 발생한다는 문제도 있었습니다. 그런데, no-PIA 기능은 PIA에서 실제로 프로그램에서 사용하는 부분만 떼서 별도 어셈블리가 아닌 호출 어셈블리 안에 넣어버리는 기능입니다. 따라서 이제 런타임 시에 더 이상 덩치 큰 PIA를 로드할 필요가 없어졌습니다.

 

매개변수에서의 ref 키워드 문제도 있었는데, 이제 더 이상 COM API를 사용할 때 일일이 ref를 선언하지 않아도 됩니다. 컴파일러가 자동적으로 해당 작업을 처리해준다는군요.

 

Variance

통상적으로 Covariance는 원래 지정된 Type대신 그 Type에서 파생된 자식 Type을 사용할 수 있게 해주는 것을 말하며, Contravariance는 그 반대 개념, 즉 지정된 Type 대신 그 Type의 상위 부모 Type을 사용할 수 있게 해주는 것을 말합니다. (양쪽 다 별도의 명시적인 Casting이 없는 경우를 말합니다)

 

예를 들어 다음과 같은 상속 구조가 있다고 가정합시다.

class Animal;

class Person : Animal;

class Man : Person;

 

어딘가에서 Person 타입을 요구한다고 가정합시다.

이 때, Person 대신 Man을 사용할 수 있게 해주는 경우가 Covariance입니다.

반대로 Person 대신 Animal을 사용할 수 있게 해주는 경우가 Contravariance가 되는거죠.

 

그리고 만약 Covariance와 Contravariance가 둘 다 되지 않는 경우, 즉 위의 예제에서 무조건 Person 타입만 써야 하는 경우를 Invariant라고 합니다.

 

C# 3.0까지는 Generic에 대해서는 Invariant였습니다. 그런데, C# 4.0에서는 Generic에 대해서 Covariance 및 Contravariance가 지원됩니다. 보다 자세한 내용은 New Features in C# 4.0의 내용이나, Eric Lippert의 블로그를 참조하시기 바랍니다. 

 

C# 5.0?

헉, 끔찍하시죠? ^^

사실 C# 4.0이 논의될 시점에 C# MVP들과 Microsoft C# 팀 간에 별도의 뉴스 그룹이 만들어져서 매우 긴 토론이 있었습니다. C# Future나 Connect, Forum 등에서도 다양한 의견과 논의가 제시되었습니다.

 

그 중 많이 얘기된 내용이 typedef의 지원이라거나, partial property, 언어/컴파일러 레벨에서의 AOP 지원, auto-implemented property에서 get이나 set 중 하나만 설정할 수 있게 해달라거나 backing store에 접근할 수 있게 해달라거나.. 다양한 요청이 있었습니다.

위에서 일부 기능들의 경우, C# 4.0에 반영이 되지 않았을까 싶었는데, 결국 현재 C# 4.0은 위에서 소개한 기능들로 사양이 정해진 것 같습니다.

 

프로그래밍 언어 얘기가 때로 재밌기도 한데, 어떻게 보면 너무 academic해보기도 하네요. C# 언어에 대한 얘기는 당분간 여기서 끝을 맺도록 하겠습니다. ^^


출처 : http://blog.naver.com/saltynut/120097115880