본문 바로가기
프로그래밍/C#

C# 지연 초기화(lazy initialization)

by bantomak 2024. 4. 4.

C# 지연 초기화

지연 초기화(lazy initializtion)는 사용 시점까지 개체 생성을 연기하는 최적화 기법이다. 즉, 멤버에 대한 액세스가 이뤄지기 전에는 초기화되지 않는 개체를 정의하는 셈이다. 이를 위해 C#에서는 C# 4.0에 이르러 Lazy<T> 클래스를 도입했다. 다음 코드는 지연 초기화를 알아보기 위한 예제이다.

 

using System;

public partial class Program
{
    static void Main(string[] args)
    {
        LazyInitName("Matthew Maxwell");
    }

    private static void LazyInitName(string NameOfPerson)
    {
        Lazy<PersonName> pn = new Lazy<PersonName>(() => new PersonName(NameOfPerson));

        Console.WriteLine("Status: PersonName has been defined.");

        if (pn.IsValueCreated) 
        {
            Console.WriteLine("Status: PersonName has been initialized.");
        }
        else
        {
            Console.WriteLine("Status: PersonName hasn`t been initialized.");
        }

        Console.WriteLine(String.Format($"Status: PersonName.Name = {(pn.Value as PersonName).Name}"));

        if (pn.IsValueCreated) 
        {
            Console.WriteLine("Status: PersonName has been initialized.");
        }
        else
        {
            Console.WriteLine("Status: PersonName hasn`t been initialized.");
        }
    }

    public class PersonName
    {
        public string Name { get; set; }
        public PersonName(string name) 
        {
            this.Name = name;

            Console.WriteLine("Status: PersonName constructor has been called.");
        }
    }
}

 

LazyInitName()은 다음과 같이 Lazy<T> 클래스를 이용해 PersonName 개체의 초기화를 지연하고 있다.

 

Lazy<PersonName> pn = new Lazy<PersonName>(() => new PersonName(NameOfPerson));

 

이렇게 하면 다음과 같이 직접적으로 클래스를 이용해서 변수를 정의하는 일반적인 방식과 달리 pn 변수를 정의한 후에도 초기화가 이뤄지지 않는다.

 

앞서 언급했듯이 초기화는 개체의 멤버에 대한 엑세스와 함께 진행된다. Lazy<T>는 인스턴스의 값을 가져오기 위한 Value 속성을 제공하는 한편, IsValueCreated 속성을 통해 Lazy<T>인스턴스의 값이 생성됐는지 확인할 수 있게 한다. LazyInitName() 함수에서 다음과 같이 Value 속성을 사용하고 있다.

 

pn 변수를 이용해서 인스턴스화한 PersonName 클래스의 Name 속성에 엑세스하기 위해 (pn.Value as PersonName).Name 형태의 구문을 이용한다. IsValueCreated 속성을 이용하면 PersonName 클래스의 초기화가 끝났는지 확인할 수 있다.

 

if (pn.IsValueCreated) 
{
    Console.WriteLine("Status: PersonName has been initialized.");
}
else
{
    Console.WriteLine("Status: PersonName hasn`t been initialized.");
}

 

이제 다음 코드처럼 Matthew Maxwell을 인수로 넣어서 LazyInitName 함수를 호출해 보자.

 

 

PersonName의 Name 속성 값을 가져오기 위해 Lazy<T>의 Value 속성에 액세스 하려 하면, 코드 내부적으로 Name 속성 액세스에 앞서 PersonName의 생성자를 호출한다. 이것이 세 번째와 네 번째 라인이 출력되는 이유다. 이후에 IsValueCreated 속성을 다시 확인하면 PersonName은 초기하 되어 pn 변수가 PersonName인스턴스를 가지고 있다는 것을 알 수 있다.

 

지연의 장단점

  • 불필요한 기능을 위한 초기화 시간을 절약할 수 있다.
  • 함수형 접근 방식에서는 명령형 방식에 비해 실행 순서의 중요성이 떨어지는 경우가 있으므로 프로그램을 더 효과적으로 실행할 수 있다.
  • 지연을 이용해 보다 효율적인 코드를 작성할 수 있다.

지연을 이용할 때 발성하는 단점도 숙지하자.

  • 프로그램 흐름을 예측하기 어렵고 제어가 어려워질 수 있다.
  • 지연을 구현하는 코드의 복잡성에 따른 성능 하락이 발생할 수 있다.

 

출처

 

Functional C# - 예스24

C# 개발자를 위한 함수형 프로그래밍 학습서다. 명령형 프로그래밍 방식과 함수형 프로그래밍을 비교하고, 함수형 프로그래밍을 위한 C#의 언어적 지원과 이를 이용한 실제 구현 예를 살펴보면

www.yes24.com

댓글