[C#] 32. 익명 형식(Anonymous Types) 사용법


Study/C#  2021. 9. 20. 20:03

안녕하세요. 명월입니다.


이 글은 C#에서 익명 형식(Anonymous Types) 사용법에 대한 글입니다.


클래스는 C#에서 프로그램을 만드는 데 있어서 가장 최소 단위입니다.

클래스의 기본 구조는 맴버 변수와 함수가 있고, 그 외에 프로퍼티와 델리게이트, 이벤트, 인덱스 등이 있습니다.

링크 - [C#] 09. 클래스 생성하는 방법(생성자, 소멸자)


그리고 우리가 작성된 클래스를 메모리에 인스턴스 생성하기 위해서는 new라는 키워드를 사용해서 생성하게 됩니다.

using System;

namespace Example
{
  // 예제 클래스
  class Node
  {
    // 맴버 변수 프로퍼티
    public int Data
    {
      get; set;
    }
    // 출력 함수
    public void Print()
    {
      // 콘솔 출력
      Console.WriteLine(Data);
    }
  }

  class Program
  {  
    static void Main(string[] args)
    {
      // 인스턴스 생성
      var node = new Node();
      // 인스턴스 맴버 변수에 값을 넣는다.
      node.Data = 100;
      // 출력 함수 호출
      node.Print();
      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

여기서 클래스에서 가장 중요한 부품은 맴버 변수입니다.

프로퍼티는 맴버 변수에 값을 넣기 위한 함수이고 델리게이트 이벤트, 인덱스 등도 함수의 역할에 대한 구분을 하기 위한 함수입니다.

함수라는 것은 프로그램을 구현하기 위한 실행 처리일 뿐이고, 클래스의 데이터를 보관하고 클래스의 크기를 결정하는 것은 결국 맴버 변수입니다.


그런데 그러한 사용 목적에 따라 클래스를 모두 생성하기에는 소스가 지나치게 복잡해 질 수도 있습니다.

가장 쉬운 예를 들면, 단일 목적에 의한 데이터를 넘기기 위한 클래스라면 그것을 위해 클래스를 작성하는 것은 조금 낭비일 수도 있습니다. 쉽게 함수에 데이터를 넘기는 데, 원시 데이터 만으로 파라미터를 작성하게 되면 파라미터가 길어 질 수 있는데 이를 위한 클래스를 만들게 되면 편하게 넘길 수 있습니다.

using System;

namespace Example
{
  // Print 함수의 파라미터를 위한 클래스
  class Parameter
  {
    // 프로퍼티
    public string Header { get; set; }
    // 프로퍼티
    public string Commnet { get; set; }
    // 프로퍼티
    public int Data { get; set; }
    // 프로퍼티
    public String Footer { get; set; }
  }
  class Program
  {
    // 출력 함수, 그냥 원시 데이터로 파리미터를 받는다.
    static void Print(string header, string comment, int data, string footer)
    {
      // 콘솔 출력
      Console.WriteLine(header);
      Console.WriteLine(comment + " = " + data);
      Console.WriteLine(footer);
    }
    // 출력 함수, 클래스 파리미터를 받는다.
    static void Print(Parameter param)
    {
      // 콘솔 출력
      Console.WriteLine(param.Header);
      Console.WriteLine(param.Commnet + " = " + param.Data);
      Console.WriteLine(param.Footer);
    }
    // 실행 함수
    static void Main(string[] args)
    {
      // 출력 함수 호출
      Print("Test1", "data", 10, "End");
      // 개행
      Console.WriteLine();
      // 출력 함수 호출
      Print(new Parameter()
      {
        Header = "Test2",
        Commnet = "data",
        Data = 100,
        Footer = "End"
      });
      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위 예제를 보면 첫번째 함수의 경우는 파리미터를 그냥 원시 데이터 타입으로 받습니다. 간단한 예제라서 파라미터가 4개이지만 상황에 따라 이 파라미터가 10개, 20개로도 만들 수 있습니다.

실제로 그렇게 만들게 되면 파리미터가 너무 많아져서 가독성이 상당히 많이 떨어지게 됩니다.

그래서 보통 파라미터의 데이터를 클래스로 만든 다음, 클래스로 데이터를 넘기게 되는데 장점은 소스가 간결해지고 가독성이 좋습니다.


그러나 문제는 전체 큰 프로젝트라고 생각했을 때 각 함수 파라미터를 위해서 클래스를 작성하는 것은 또 엄청난 코드 작성이 될 수 있습니다.

그래서 이러한 일회성 인스턴스를 위한 익명 형식의 클래스가 있습니다.

using System;

namespace Example
{
  class Program
  {
    // 파라미터는 var 형식으로 받을 수 없기 때문에 dynamic으로 받는다.
    static void Print(dynamic param)
    {
      // 콘솔 출력
      Console.WriteLine(param.Header);
      Console.WriteLine(param.Commnet + " = " + param.Data);
      Console.WriteLine(param.Footer);
    }
    static void Main(string[] args)
    {
      // new 키워드를 써서 인스턴스를 생성하나 클래스 명은 없다.
      var data = new
      {
        Header = "Test",
        Commnet = "data",
        Data = 100,
        Footer = "End"
      };
      // 출력 함수 호출
      Print(data);
      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

위 예제에서 Print 함수에 인스턴스를 넘길 때 new 키워드를 사용해서 인스턴스를 생성했습니다만, 클래스 명은 없네요.

파라미터는 var 타입으로 받고 Print 함수에서는 var 타입의 변수명을 사용할 수 없기 때문에 dynamic 키워드로 파라미터를 받았습니다.


예전에 var 타입과 dynamic 타입에 대해 설명한 적이 있으니 참고하세요.

링크 - [C#] 26. var 키워드와 dynamic 키워드


특히 이런 익명 형식(Anonymous Types)의 타입은 Linq 식에서 많이 사용하게 됩니다.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Example
{
  class Program
  {
    // 실행 함수
    static void Main(string[] args)
    {
      // 리스트 선언
      var list = new List<int>();
      // i가 0부터 9까지
      for (int i = 0; i < 10; i++)
      {
        // 리스트에 데이터를 삽입
        list.Add(i);
      }
      // 5 초과된 값을 익명 형식의 List 타입으로 리턴한다.
      // 반복문으로 추출
      foreach (var node in list.Where(x => x > 5).Select(x => new { Data = x }))
      {
        // 콘솔 출력
        Console.WriteLine(node.Data);
      }

      // 아무 키나 누르시면 종료합니다.
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}

여기까지 C#에서 익명 형식(Anonymous Types) 사용법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.