유니티에서의 제네릭 프로그래밍: where 키워드의 활용

where 키워드란?

 

제네릭 프로그래밍에서 중요한 역할을 하며, 제네릭 타입에 대한 제약 조건을 지정할 때 사용됩니다. 

 

where키워드를 사용함으로써 컴파일 타임에 타입의 특정 특성을 보장할 수 있게 해줍니다. 예를 들어, 특정 타입이 반드시 클래스여야 하거나 특정 인터페이스를 구현해야 한다는 등의 조건을 걸 수 있습니다.


where 키워드 예시

 

형식 설명 예시
where T : class 제네릭 타입 매개변수가 클래스여야 함 where T : class
where T : struct 제네릭 타입 매개변수가 구조체여야 함 where T : struct
where T : new() 제네릭 타입 매개변수가 매개변수가 없는 기본 생성자를 가져야 함 where T : new()
where T : SomeBaseClass 제네릭 타입 매개변수가 특정 클래스를 상속받아야 함 where T : MonoBehaviour
where T : SomeInterface 제네릭 타입 매개변수가 특정 인터페이스를 구현해야 함 where T : IComparable
where T : U 제네릭 타입 매개변수가 다른 제네릭 타입 매개변수 U를 상속받아야 함 where T : MonoBehaviour, new()
where T : class, SomeInterface, new() 여러 제약을 조합하여 사용할 수 있음 where T : class, IComparable, new()

 


where T : class

제네릭 타입 매개변수가 클래스여야 합니다.

public class MyClass<T> where T : class
{
    // 클래스 제약을 가진 제네릭 클래스의 예시
}

 

// MyClass 클래스를 활용한 코드
MyClass<string> myStringClass = new MyClass<string>(); // "가능", string은 참조 타입(클래스)이다
MyClass<int> myIntClass = new MyClass<int>();         // "에러", int는 클래스가 아님, 값 타입(구조체)이다

 


where T : struct

제네릭 타입 매개변수가 구조체여야 합니다.

public class MyStructContainer<T> where T : struct
{
    private T _value;

    public MyStructContainer(T value)
    {
        _value = value;
    }
}

 

// MyStructContainer 클래스를 활용한 코드
MyStructContainer<int> intContainer = new MyStructContainer<int>(10); // 가능
MyStructContainer<string> stringContainer = new MyStructContainer<string>("Hello"); // 에러: string은 구조체가 아님

 


where T : new()

제네릭 타입 매개변수가 매개변수가 없는 기본 생성자를 가져야 합니다.

public class Factory<T> where T : new()
{
    public T CreateInstance()
    {
        return new T();
    }
}

 

// Factory 클래스를 활용한 코드
Factory<int> intFactory = new Factory<int>();         // 가능: int는 기본 생성자를 가짐
Factory<string> stringFactory = new Factory<string>(); // 가능: string은 기본 생성자를 가짐

 

기본 생성자(Default Constructor)는 매개변수를 받지 않고 객체를 생성하는 생성자를 말합니다. 기본 생성자는 클래스에 직접 정의되지 않은 경우에도 컴파일러에 의해 자동으로 생성됩니다. 하지만, 클래스에 다른 생성자가 명시적으로 정의된 경우에는 기본 생성자가 자동으로 생성되 않습니다.

 

기본 생성자가 생성되는 경우는 다음과 같습니다.

public class MyClass
{
    // 기본 생성자
    public MyClass()
    {
        // 초기화 코드
    }
}

 

public class MyClass
{
    // 기본 생성자는 컴파일러에 의해 자동으로
    // 만들어진다
}

 

 

반면에, 다음과 같이 매개변수를 받는 생성자만 있는 경우에는 기본 생성자가 자동으로 생성되지 않습니다.

public class MyClass
{
    // 매개변수를 받는 생성자
    public MyClass(int value)
    {
        // 초기화 코드
        // 이때는 기본 생성자가 생성되지 않는다.
    }
}

 

 

🔽객체에 대한 내용은 아래 포스팅을 참고해주세요!

 

유니티 C# OOP와 SOLID에 대해 알아보자 #디자인패턴

OOP란?Object-Oriented Programming의 약자로 한글로 설명하면 객체 지향 프로그래밍이라는 뜻입니다.현실 세계의 객체를 모델링하여 소프트웨어를 개발하는 방법론입니다. 현실 세계의 객체라..?🤔객

wlsdn629.tistory.com

 


where T : SomeBaseClass

제네릭 타입 매개변수가 특정 클래스를 상속받아야 합니다.

 

public class BaseClass
{
    // 기본 클래스의 내용
}

public class DerivedClass : BaseClass
{
    // 파생 클래스의 내용
}

public class MyClass<T> where T : BaseClass
{
    // SomeBaseClass 제약을 가진 제네릭 클래스의 예시
}

 

// MyClass 클래스를 활용한 코드
MyClass<BaseClass> baseClassInstance = new MyClass<BaseClass>();       // 가능
MyClass<DerivedClass> derivedClassInstance = new MyClass<DerivedClass>(); // 가능
MyClass<int> intClassInstance = new MyClass<int>();                   // 불가능: int는 SomeBaseClass를 상속받지 않고 있기 때문

where T : SomeInterface

제네릭 타입 매개변수가 특정 인터페이스를 구현해야 합니다.

 

public interface IMyInterface
{
    // 인터페이스의 내용
}

public class MyClass<T> where T : IMyInterface
{
    // SomeInterface 제약을 가진 제네릭 클래스의 예시
}

 

// MyClass 클래스를 활용한 코드
MyClass<IMyInterface> interfaceInstance = new MyClass<IMyInterface>(); // 가능
MyClass<int> intInstance = new MyClass<int>();                       // 불가능: int는 IMyInterface를 구현하고 있지 않기 때문

where T : U

제네릭 타입 매개변수가 다른 제네릭 타입 매개변수 U를 상속받아야 합니다.

 

public class BaseClass
{
    // 기본 클래스의 내용
}

public class DerivedClass : BaseClass
{
    // 파생 클래스의 내용
}

public class MyClass<T, U> where T : U
{
    // T가 U를 상속받는 경우의 예시
}

 

// MyClass 클래스를 활용한 코드
MyClass<DerivedClass, BaseClass> derivedInstance = new MyClass<DerivedClass, BaseClass>(); // 가능
MyClass<BaseClass, DerivedClass> baseInstance = new MyClass<BaseClass, DerivedClass>();   // 불가능: BaseClass가 DerivedClass를 상속받지 않고 있기 때문

 


where T : class, SomeInterface, new()

여러 제약을 조합하여 사용할 수 있습니다.