IT/학습

제네릭(Generic)

wh011202 2024. 12. 12. 17:54
제네릭이란?

 

제네릭(Generic)은 특정 데이터 타입에 의존하지 않고 다양한 타입을 다룰 수 있는 방법이다.

 

제네릭을 사용하면 코드의 재사용성이 높아지고, 컴파일 시 타입 안정성을 제공하며, 런타임 오류를 줄일 수 있다.

제네릭은 주로 클래스, 메서드, 인터페이스에서 사용된다고 한다.

 

제네릭 : 하나의 클래스가 다양한 형태의 자료형을 처리할수 있게됨.

 

C#에서 제네릭을 사용하는 예를 들어보면 다음과 같다.

 

제네릭 클래스

public class GenericClass<T>
{
    private T data;

    public GenericClass(T value)
    {
        data = value;
    }

    public T GetData()
    {
        return data;
    }
}

 

위의 코드는 그냥 기본 틀이다. 아래의 작성된 코드를 가지고 예를 들어보자.

 

컵은 액체를담는다. 그러나 이것저것 다넣을수잇다. 라는걸 예시로 담기위해 아래 클래스를 만들었다.

class Milk
{
    public string _ExpireDate;

    public Milk(string ExpireDate) 
    {
        _ExpireDate = ExpireDate;
    } 
    public Milk() { }
}

class Coffee
{
    public string CoffeeType;
}

class Water
{
    public string WaterName;
}

class PaperClip
{
    public string Material;
}

이제 이 위에것들이 아래 클래스에 사용될수 있게될것이다.

   class Cup<T>  where T : class// T에 class만 들어올수 있다.
   {
       T _contents;
       float _fillAmount;

       public T GetContents()
       {
           return _contents;
       }
   }

 

            Cup<Milk> milkCup = new Cup<Milk>();

            Cup<Milk, int> milkIntCup = new Cup<Milk, int>();

            Cup<Water> waterCup = new Cup<Water>();

            milkCup.GetContents()._ExpireDate = "asdf";
            waterCup.GetContents().WaterName = "sdaf";

위에있는것처럼 T 부분에 사용할 클래스명을 넣고 바로바로 쓸수있다.

 

우리가 일일이 만들 필요가 없어지는것이다.

 

그리고 아래처럼 쓸수도 있다.

 

 class Cup<T, U> 
     where T : class , new()//T에 class형식만 들어오고 ,
     					//인자값을 요구하지 않는 생성자가 있는 클래스만 들어올수 있게끔 제약.
     where U : struct //이렇게도 된다. 다만 where는 하나당 하나씩쓰는게 좋다.
 {
     T _contents = new T();
     U _fillAmount;

     public T GetContents()
     {
         return _contents;
     }

     public void SetFillAmount(U amount)
     {
         _fillAmount = amount;
     }
 }

 

 음 이렇게 쓰면 복잡해질수 있으므로 추천은 하지 않는단다.

 

 

제네릭 메서드

 이것도 기본틀이다. data는 그냥 인자값의 변수명 정도로 생각하면 될것이다.
public class GenericMethodClass
{
    public void ShowData<T>(T data)
    {
        Console.WriteLine(data);
    }
}

제네릭 인터페이스

 음 인터페이스는 잘 모르지만 이것 또한 그대로 사용가능한듯하다.
public interface IGenericInterface<T>
{
    T ProcessData(T data);
}

제네릭을 사용하면 데이터 타입을 명시적으로 정의하지 않고도 다양한 타입의 데이터를 처리할 수 있다.

예를 들어, List<T>는 다양한 타입의 리스트를 관리할 수 있다고 한다.

 

제네릭은 코드를 더 유연하고 재사용 가능하게 하며, 타입 안전성을 제공하여 개발자의 실수를 줄이는 데 큰 도움이 된단다.

 

자 그럼 이걸 어떤때 쓰냐는걸 요약해보자.

 

여러 데이터 형식에 동일한 로직을 적용할때. 라고 요약을 해볼수 있겠다.

 

물론 내가 모르는 사용용도가 더 있다고 하는데 읽어는 봤지만 아직 써본 코드가 없기 때문에 나중에 써먹으면 추가로 C#코드 란에 추가할 예정이다.

 

 

아래는 면접때 제네릭에 대해서 자주 묻는 질문을 강사님이 준비 해주셔서  Copilot를 돌려서 물어본 내용이다.

이후 다른 블로그들도 찾아봤지만 이게 제일 깔끔해서 가져와 보았다.

 

1. 제네릭(Generic)은 어디에 왜 쓰나요? 어떤 이점을 제공하죠?

제네릭은 프로그래밍에서 매우 중요한 역할을 하며, 여러 면에서 이점을 제공합니다.

다음은 제네릭이 사용되는 주요 영역과 이유, 그리고 제공하는 이점들입니다:

  • 타입 안전성: 컴파일 시점에 타입 검사를 수행하여 런타임 오류를 줄일 수 있습니다.
  • 코드 재사용성: 동일한 코드를 다양한 데이터 타입에 대해 재사용할 수 있습니다.
  • 가독성 향상: 명확하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

예를 들어, List<T>는 다양한 타입의 리스트를 지원합니다.

2. 제네릭에서 타입 제약 조건은 무엇이고, 왜 사용하나요?

제네릭 타입에 특정 제약 조건을 걸어 해당 타입이 특정 인터페이스를 구현하거나 특정 베이스 클래스를 상속받도록 할 수 있습니다. 이는 제네릭 클래스나 메서드가 해당 타입의 멤버를 안전하게 사용할 수 있도록 합니다.

 

예시:

public class Repository<T> where T : IEntity
{
    public void Add(T item)
    {
        // IEntity 인터페이스의 멤버를 안전하게 사용 가능
    }
}

위 코드에서 T는 IEntity 인터페이스를 구현해야 하며, 이는 Repository 클래스가 IEntity의 멤버를 사용할 수 있게 해줍니다.

3. 제네릭과 박싱/언박싱의 관계는 무엇인가요? 제네릭이 박싱을 어떻게 줄여주나요?

박싱(Boxing)은 값 타입을 객체 타입으로 변환하는 과정이며, 언박싱(Unboxing)은 그 반대 과정입니다.

이는 성능에 부담을 줄 수 있습니다.

 

제네릭은 박싱과 언박싱을 줄이는 데 도움을 줍니다.

 

제네릭을 사용하면 값 타입을 포함한 어떤 타입이든 타입 안전성을 유지하면서 컬렉션에 저장할 수 있으며, 이 과정에서 박싱이 필요하지 않습니다. 예를 들어, List<int>는 int 값을 박싱 없이 저장할 수 있습니다.

박싱과 언박싱의 예:

 
ArrayList list = new ArrayList();
list.Add(1); // 박싱 발생

int value = (int)list[0]; // 언박싱 발생

제네릭을 사용한 경우:

 
List<int> list = new List<int>();
list.Add(1); // 박싱 발생하지 않음

int value = list[0]; // 언박싱 발생하지 않음

이로 인해 제네릭을 사용하면 성능이 향상되고, 코드가 더 안전하고 효율적으로 작성될 수 있습니다.

 

 

 

개인적으론 제네릭을 사용하는이유는 

 

여러 클래스들의 모음을 사용하는게 제일 클거같다.

우리가 코딩을 하다보면 비슷하지만 다른 코드들을 뭉쳐야할때가 있는데 저걸 일일이 생각하면서 찾고 하는것보단 이렇게 T 를 써서 임의로 사용할수 있게 해주는게 정말 좋은것같다.

 

그리고 제약조건 같은경우는 안하면 제대로 사용을 하지못하는데 , 아마 이게 코드의 안정성을 올려주는 것같다.

 

박싱 언박싱으로 사용하던걸 ms 에서 안전하게 사용할수있게 만들어 준것 같은데 정말 고맙게 잘쓸듯하다 ㅎㅎ

 

아무튼 오늘도 머리아프지만 신기하고 좋은 사용방법을 하나 더 배웠다...