본문 바로가기

IT 살이/04. 기술 - 프로그래밍

LINQ 시리즈 05 - Object initializer, 익명 타입(anonymous types) I

현재 시리즈 제목 "LINQ시리즈"이다. 그러나 아직 본격적인 LINQ에는 들어가지도 못하고 있다. 지금 하나씩 설명하고 있는 단위 기술들 델리게이트, 익명 메소드, 제네릭, 타입 유추, 익명 타입 그리고 앞으로도 배울 람다 표현식을 포함한 몇 가지는 그 자체만으로도 가치가 있는 기술들이기는 하지만 뒤에서 설명할 LINQ에서 조합되어서 그 효과를 발휘하게 될 것이다. 그래서 표현식은 아조 아조 심플하게 변하게 된다. 한번 더 볼까나.

var query =

    from c in customers

    where c.Discount > 3

    orderby c.Discount

    select new { c.Name, Perc = c.Discount / 100 };

이렇게 간단한 표현속에 그렇게 많은 개념과 기술이 들어가 있을 줄이야. 필자도 미처 몰랐다.  이젠 좀 지겹기는 하다.  할것도 많은데. LINQ에 대한 본격적인 공부도 해야 하고. 그리고 필자의 원래의 목표였던 프레임워크 주제 특히 이번에는 Spring.NET에 대한 공부도 계속 하야 하는데. 그러나 이 표현식을 그냥 대충 넘어갈 수는 없을 것 같다. 완벽히 이해해야 할 것 같다. 그래야 앞으로의 개발자 생활이 편해질 것이라는 것이 필자의 동물적 생존 본능으로 느껴지고 있다. 빠샷!

오늘 Object initializer, 익명타입(anonymous type)이란 것을 함께 알아보자. 이 두 녀석도 철저히 코드를 심플하게 만들기 위한 개념들이다. 객체를 생성할때 그 내부 상태를 특정 상태로 초기화시켜 주고 싶다면 보통 파라미터가 있는 생성자(Constructor)를 사용합니다.  다음과 같은 타입이 있다고 하겠다.

public class Customer

{

    public string Name;

    public string City;

    public int Age ;

    public Customer(){}

    public Customer(string name, int age)

    {

        this.Name = name;

        this.Age = age;

    }

}

Customer의 객체는 name, age 파라미터를 갖는 생성자를 통해서 초기화될 수 있다. 만약 age가 아니라 city값을 초기화하고 싶다면 앞의 생성자 대신에 파라미터가 없는 기본 생성자와 공개적으로 노출된 속성을 통해 설정하는 다음과 같은 코드가 필요하다.

Customer c = new Customer();

c.Name = "Bart";

c.City = "Ghent";

C#3.0부터는 이렇게 객체를 초기화하는 코드를 간단히 할 수 있는 폼을 제공하고 있다.

Customer c = new Customer{ Name = "달봉이", City="Seoul" };

이런 표현을 Object initializer라고 한다. 인자가 없는 기본 생성자와 상태 설정이 필요한 값을 공개 속성 또는 필드로 노출시켜 두면 된다. 이 코드는 컴파일되어 IL코드로 되면 앞의 코드의 컴파일 결과와 동일해진다. {}사이에 명시된 이름들은 초기화되는 객체에서 공개적으로 노출한 속성 또는 필드에 해당한다.

앞에서처럼 타입과  시작 브래킷{ 사이에 ()이 없는 경우는 기본 생성자를 호출한다. 그러나 인자가 있는 생성자를 호출할 수도 있다.

// 파라미터가 있는 생성자를 초기화에 사용할 수도 있다.

Customer c = new Customer( "달봉이", 100 ) { City="Seoul" };

object initializer를 사용하면 함수 형태로 객체 초기화를 마무리할 수 있다. 즉 다른 문장을 사용하지 않고도 하나의 문장으로 복잡한 초기화를 끝낼 수 있다. 다음 코드를 보자.

Customer c = new Customer{

    Name = "Bart",

    Age = 23,

    Address = new Address {

                   Street = "Andersstreet",

                   Number = 60,

                   PostalCode = 9000,

                   City = "Ghent"

                }

  };

이렇게 객체안에 포함된 다른 객체의 초기화 코드도 하나의 문장으로 마무리될 수 있다. 이 표현도 다시 간단하게 변할 수 있는데, 내부의 중첩된 객체의 생성에서는 new를 없앨 수 있다. 최외곽의 생성자에서만 new를 사용해도 된다.

Customer c = new Customer{

    Name = "Bart",

    Age = 23,

    Address = {

                    Street = "Andersstreet",

                    Number = 60,

                    PostalCode = 9000,

                    City = "Ghent"

                }

  };

C#1.X에서도 이런 비슷한 표현이 있었다. 그러나 배열 생성에만 제한되어 있었다.

string[] names = {"달봉이", "봉달이", "봉봉이"};

이런 표현의 initializer는 컬렉션에서 자주 사용된다.

List<Customer> list = new List<Customer>{

    new Customer("달봉이", 100){ City = "Seoul"},

    new Customer{Name="봉달이"},

    new Customer{ Name = "봉봉이" City = "Seoul"},

};

요약하면, LINQ에서는 주로 그 쿼리의 대상들이고 그리고 그 쿼리 결과도 컬렉션으로 반환되는 경우가 많다. object initializer 표현은 LINQ에서 광범위하게 사용된다.  익명 타입(anonymous type)은 objct initializer로 인해서 심플해진 표현을 더 심플하게 해 준다.

포스트가 너무 길어진다. 익명 타입은 다음 포스트로 넘기자.