[C#] 일반화 프로그래밍 (2)

Flaming Bun·2025년 4월 18일

C#

목록 보기
13/35

참고 영상: https://www.youtube.com/watch?v=G3Edvvp_YpA&list=PLVsNizTWUw7GN8wPRhclbKuQa9aI9Cj2V&index=12

🔥 형식 매개 변수 제약

형식 매개 변수 T가 아무 타입이나 될 수 있지만, 어떤 기능을 사용하려면 특정 타입 또는 조건을 만족해야 할 때가 있다.

이때 제약을 걸면 T특정 조건을 갖춰야만 사용할 수 있다.

문법: where 형식매개변수: 제약조건

Where절과 함께 사용할 수 있는 제약조건

제약설명
where T : structT는 값 형식이어야 한다.
where T : classT는 참조 형식이어야 한다.
where T : new()T는 반드시 매개 변수가 없는 생성자가 있어야 한다.
where T : 기반 클래스 이름T는 명시한 기반 클래스의 파생 클래스여야 한다.
where T : 인터페이스 이름T는 명시한 인터페이스를 반드시 구현해야 한다. 인터페이스에는 여러 개의 인터페이스를 명시할 수 있다.
where T : UU는 클래스 또는 인터페이스가 될 수 있으며, T는 U로부터 상속받은 클래스여야 한다.

⚔ where T : struct - T를 값 형식으로 제약

class MyValue<T> where T : struct
{
    public void PrintValue()
    {
        T value = default(T); // default(T) - T가 float이면  value는 0.0f
        Console.WriteLine(value);
    }
}
// 사용 예시
var myValue = new MyValue<int>();

📌 default(T)

default(T)T가 어떤 타입이든지 그 타입에 맞는 초기값을 갖는다.
ex) Tint인 경우 default(T)0이다.


⚔ where T : class - T를 참조 형식으로 제약

class MyReference<T> where T : class
{
    public void PrintTypeName(T obj)
    {
        Console.WriteLine(obj.GetType().Name);
    }
}
// 사용 예시
var myReference = new MyReference<string>(); 

⚔ where T : new() - T는 매개변수 없는 생성자를 가져야 한다.

T타입 객체를 생성하고 싶을 때 해당 객체가 T() 생성자를 가지고 있다는 보장이 없기때문에 new T()를 제약 없이 사용하면 컴파일 에러가 발생한다.

new T()를 사용하려면 where T : new() 제약이 필요하다.

class Creatable<T> where T : new()
{
    public T Create()
    {
        return new T();
    }
}
// 사용 예시
class Person
{
    public string Name { get; set; } = "Unknown";
}

var creator = new Creatable<Person>();
var p = creator.Create();

⚔ where T : 기반 클래스 이름 - T는 지정한 클래스 또는 파생 클래스여야 한다.

class Animal
{
    public virtual void Say() => Console.WriteLine("Animal sound");
}

class Dog : Animal
{
    public override void Say() => Console.WriteLine("Mung");
}

class AnimalSoundBox<T> where T : Animal
{
    public void MakeSound(T animal)
    {
        animal.Say();
    }
}
// 사용 예시
var animalSoundBox = new AnimalSoundBox<Dog>(); // 이 순간 MakeSound(Dog animal)로 변경

animalSoundBox.MakeSound(new Dog());

⚔ where T : 인터페이스 이름 - T는 명시한 인터페이스를 구현해야 한다.

interface IWalkable
{
    void Walk();
}

class Human : IWalkable
{
    public void Walk() => Console.WriteLine("Walking...");
}

class Walker<T> where T : IWalkable
{
    public void StartWalk(T obj)
    {
        obj.Walk();
    }
}
// 사용 예시
var walker = new Walker<Human>();
walker.StartWalk(new Human()); // 출력: Walking...

⚔ where T : U - T가 반드시 U를 상속하거나, U를 구현한 타입이어야 한다.

U가 클래스라면, TU를 상속해야 한다.

U가 인터페이스라면, TU를 구현해야 한다.

class Animal
{
    public void Eat() => Console.WriteLine("Eating");
}

class Dog : Animal
{
    public void Bark() => Console.WriteLine("Woof!");
}

// T는 반드시 U를 상속해야 함
class AnimalTrainer<T, U> where T : U
{
    public void Train(T animal)
    {
        Console.WriteLine("Training...");
    }
}
// 사용 예시
var trainer = new AnimalTrainer<Dog, Animal>();
trainer.Train(new Dog()); 

0개의 댓글