본문 바로가기

C#

C# 3.0의 발전 (2) - Object and Collection Initializer

지난번 알아보았던 자동구현 프로퍼티(Auto-Implemented Properties)는 그동안 개발자들을 귀찮게 하던 멤버변수와 멤버변수에 대한 엑세스를 지원하는 프로퍼티를 생성하는데 좀 더 간결하게 표현할 수 있도록 해는 것이었다면 이번에 볼 객체와 컬렉션에 대한 이니셜라이저(Object and Collection Initializer)는 객체 또는 컬렉션의 생성을 좀더 직관적으로 할 수 있도록 해줍니다.

C# 2.0까지 객체를 생성할때 객체내의 멤버들을 동적으로 초기화 시키기 위해서는 생성자의 매개변수를 사용하거나, 생성후 객체의 각 멤버에 대해서 직접 값을 할당해주는 방법을 사용하였습니다만, C# 3.0의 Object and Collection Initializer는 생성자의 선언없이도 생성과 동시에 해당 객체나 컬렉션에 대한 초기화가 가능해지는 것입니다. 실제 코드를 보면 쉽게 이해가 가능하실 겁니다.

[코드 1-1 : C# 3.0 이전의 객체 초기화]

    1 public class Customer

    2 {

    3     private int custKey;

    4     private string name;

    5     private string address;

    6 

    7     public int CustKey { get { return custKey; } }

    8     public string Name

    9     {

   10         get { return name; }

   11         set { name = value; }

   12     }

   13     public string Address

   14     {

   15         get { return address; }

   16         set { address = value; }

   17     }

   18 }

   19 

   20 public class Program

   21 {

   22     static void Main(string[] args)

   23     {

   24         Customer customer = new Customer();

   25         customer.Name = "오성민";

   26         customer.Address = "서울시 구로구";

   27     }

   28 }

위의 코드는 언제나 보던 일반적인 코드입니다. 객체를 생성한 후 해당 객체의 멤버에 값을 할당하는 것이죠. 이 코드를 Object and Collection Initializer를 이용한 코드로 바꾼다면 아래와 같이 됩니다.

[코드 1-2 : C# 3.0 의 Object and Collection Initializer를 이용한 초기화

    1 public class Customer

    2 {

    3     public int CustKey { get; private set; }

    4     public string Name { get; set; }

    5     public string Address { get; set; }

    6 }

    7 

    8 public class Program

    9 {

   10     static void Main(string[] args)

   11     {

   12         Customer customer = new Customer

   13         {

   14             Name = "노휘겸",

   15             Address = "서울시 관악구"

   16         };

   17     }

   18 }

지난번에 보았던 자동구현 프로퍼티를 이용하여 Customer 클래스를 작성하였고, 이 클래스의 객체를 생성하는 시점에서 Customer객체의 내부 멤버들의 값을 할당하였습니다.

Object and Collection Initializer의 구성은 여러개의 멤버에 대한 이니셜라이저가 ,(콤마)로 구분되어 있으며, 이니셜라이저 외부에는 "{", "}"로 둘러싸여 구성되어 있습니다.
이니셜라이저는 접근이 가능한 멤버나 프로퍼티에 대해서만 값의 할당이 가능합니다.
즉, 위의 코드에서 본다면 set이 private 으로 구성된 CustKey의 경우에는 CustKey = 1 로 할당 할 수 없는 것입니다.
그리고, 한번에 같은 멤버를 두번이상 할당할 시에는 오류가 발생하게 됩니다.

아래는 위보다 조금 복잡한 사용예입니다.

[코드2]

    1 public class Point

    2 {

    3     public int X { get; set; }

    4     public int Y { get; set; }

    5 }

    6 

    7 public class Line

    8 {

    9     public Point P1 { get; set; }

   10     public Point P2 { get; set; }

   11 }

   12 

   13 public class Triangle

   14 {

   15     private Point p1 = new Point();

   16     private Point p2 = new Point();

   17     private Point p3 = new Point();

   18 

   19     public Point P1 { get { return p1; } set { p1 = value; } }

   20     public Point P2 { get { return p2; } set { p2 = value; } }

   21     public Point P3 { get { return p3; } set { p3 = value; } }

   22 }

   23 

   24 public class Program

   25 {

   26     static void Main(string[] args)

   27     {

   28         Line line = new Line

   29         {

   30             P1 = new Point { X = 1, Y = 1 },

   31             P2 = new Point { X = 4, Y = 4 }

   32         };

   33 

   34         Triangle triangle = new Triangle

   35         {

   36             P1 = { X = 0, Y = 0 },

   37             P2 = { X = 5, Y = 5 },

   38             P3 = { X = 5, Y = 0 }

   39         };

   40     }

   41 }

위와 같이 이니셜라이저 안에서 또다른 객체의 이니셜라이저가 존재할 수도 있으며, 이미 생성된 객체의 경우에는 값의 할당이 바로 이루어질 수도 있습니다.
line 객체의 경우 P1, P2 Point 객체가 생성되지 않았으므로 new Point {...}으로 생성과 함께 할당을 하였으나, triangle 객체의 경우에는 이미 Point 클래스의 객체들이 이미 생성되어 있으므로 생성하는 부분을 생략하고 바로 값을 할당하고 있음을 볼 수 있습니다.

만일 [코드1-2]에서와 같이 CustKey처럼 외부에서 할당이 불가능하고 생성자의 파라미터를 통해서 값을 할당해야 할때도 사용이 가능할까요?
물론 사용이 가능합니다. 생성자가 있다고 해서 달라질것은 생성자에 파라미터에 해당하는 값을 전송하면 되는 것이죠.

public class Customer

{

    public int CustKey { get; private set; }

    public string Name { get; set; }

    public string Address { get; set; }


    public Customer(int custKey)

    {

        CustKey = custKey;

    }

}


Customer customer = new Customer(1) { Name = "노휘겸", Address = "서울" };


만일 생성자에서 값이 할당된 멤버를 다시 이니셜라이저에서 값을 할당하면 이니셜라이저에서 할당한 값으로 설정이 됩니다.

이름이 Object and Collection Initializer 이므로 이제 컬렉션을 이용하는 코드를 보도록 하죠. 다들 예상하시겠지만, Collection이라고 해서 다른게 없이 위의 이니셜라이저 안에서 또 다른 이니셜라이저를 사용하는 것과 동일합니다.

    1 List<Customer> customers = new List<Customer>

    2 {

    3     new Customer(1) { Name = "노휘겸", Address = "서울" },

    4     new Customer(2) { Name = "류순필", Address = "마산" },

    5     new Customer(3) { Name = "황원준", Address = "오산" }

    6 };

Customer객체가 담기는 Generic List의 생성을 한번에 완료시켰습니다. 만일 이 코드를 C# 2.0의 코드로 작성한다면

    1 List<Customer> customers = new List<Customer>();

    2 Customer customer1 = new Customer(1);

    3 customer1.Name = "노휘겸";

    4 customer1.Address = "서울";

    5 customers.Add(customer1);

    6 ......

위와 같은 형태가 되겠죠? 보시는 여러분들이 판단하실 부분이긴 하지만, 제 주관적으로는 상당히 직관적이고 코드 읽기가 수월할 듯 하네요.

지난번 Auto-Implemented Properties 와 이번의 Object and Collection Initializer 의 경우 감탄을 자아낼 만큼 대단한 기능은 아니지만, C#의 언어의 표현력을 향상시켜주는 것 같습니다.

궁금한점이나 지적사항이 있으면 댓글로 남겨주세요.