[HCI] 7주차 제네릭

정수현·2025년 4월 30일

C#

목록 보기
8/10

2025-04-25


📍 제네릭

  • 특정 타입에 의존하지 않고 어떤 타입이든 들어올 수 있도록 설계하는 방법 (타입을 나중에 넣는 방식)
    <T> <K> <V> : 타입 매개 변수 요소 타입을 일반화한 타입

🍀 제네릭 클래스 사례

  • 제네릭 리스트 : List<T>
  • T에 특정 타입으로 구체화
  • 정수만 다루는 리스트 : List<int>
  • 문자열만 다루는 리스트 : List<string>
  • Person만 다루는 리스트 : List<Person>

⇒ 다양한 자료혀엥 적용될 수 있는 일반화된 타입 매개변수로 클래스나 메소드를 작성하는 기법이다.

🍀 제네릭 예제

💡 제네릭은 사용할 자료형을 매개변수로 전달받는다.

public class IntStack
{
	int[] items;
    int count;
    public void Push(int item) { ... }
    public int Pop() { ... }    
}

public class StringStack
{
	string[] items;
    int count;
    public void Push(string item) { ... }
    public string Pop() { ... }
}

public class Stack<T>
{
	T[] items;
    int count;
    public void Push(T item) { ... }
    public T Pop() { ... }
}

...

Stack<int> istack = new Stack<int>();
istack.Push(3);
int x = istack.Pop();

Stack<string> sstack = new Stack<string>();
sstack.Push("C#");
string s = sstack.Pop();



📍 제네릭 클래스

클래스나 인터페이스 선언부에 일반화된 타입을 추가한다.

public class MyClass<T>
{
	T val;
    
    void Set(T a)
    {
    	val = a;
    }
    
    T Get()
    {
    	return val;
    }
}
  • 제네릭 클래스 MyClass를 선언, 매개변수 T
  • val의 타입은 T
  • T 타입의 값 aval에 지정
  • T 타입의 값 val 리턴



📍 구체화

제네릭 타입의 클래스에 구체적인 타입을 대입하여 객체를 생성한다.

🍀 제네릭 타입 T에 string 지정

MyClass<string> s = new MyClass<string>();
s.Set("Hello");
Console.WriteLine(s.Get()); // Hello

🍀 제네릭 타입 T에 int 지정

MyClass<int> n = new MyClass<int>();
n.Set(5);
Console.WriteLine(n.Get()); // 5

🍀 구체화된 MyClass<string> 소스 코드

public class MyClass<T>
{
	T val;
    void Set(T a) { val = a; }
    T Get() 	  { return val; }
}
public class MyClass<string>
{
	string val;
    void Set(string a) { val = a; }
    string Get() 	   { return val; }
}
  • 변수 val 타입 : string
  • string 타입의 값 aval에 지정
  • string 타입의 값 val을 리턴

💡 제네릭 타입을 선언할 때, 인자 타입을 지정할 수 있다.

  • 값 형식인지 참조 형식인지 or 어떤 특정 부모 클래스로부터 파생된 타입인지 or 어떤 인터페이스를 구현한 타입인지
  • where T : 제약 조건

🍀 인자 타입 지정 예제

  • 값 형식 T
    class MyClass<T> where T : struct
  • 참조 형식 T
    class MyClass<T> where T : class
  • default constructor
    class MyClass<T> where T : new()
  • MyBaseClass의 파생 클래스이어야 한다.
    class MyClass<T> where T : MyBaseClass
  • IComparable 인터페이스를 가져야 한다.
    class MyClass<T> where T : IComparable
  • 복수 타입 파라미터 제약
    class MyClass<T> where T : struct where V : class
  • 여러 개 제약
    class MyClass<T> where T : Person, I Comparable<T>, new()



📍 불변성과 가변성

  • 불변성 : 타입이 정확히 일치해야만 한다.ㅌ
List<Dog> odgs = new List<Dog>();
List<Animal> animals = dogs; // 에러
  • 가변성 : 타입이 정확히 일치하지 않아도, 레퍼런스를 변환할 수 있다.
    → 공변성 or 반공변성으로 나뉜다.
  • 공변성 : 하위 타입 → 상위 타입으로 레퍼런스 변환할 수 있는 것
    ⇒ 자식 타입을 부모 타입처럼 쓸 수 있다. (out 키워드)
IEnumerable<Dog> dogs = new List<Dog>();
IEnumerable<Animal> animals = dogs;
  • 반공변성 : 상위 타입 → 하위 타입으로 레퍼런스를 변환할 수 있는 것
    ⇒ 부모 타입을 자식 타입처럼 쓸 수 있다. (in 키워드)
IComparer<Animal> animalComparer = new AnimalComparer();
IComparer<Dog> dogComparer = animalComparer; 



📍 공변성과 반공변성

공변성을 지원하는 제네릭 인터페이스

  • IEnumerable<out T>
  • IEnumerator<out T>
  • IQueryable<out T>
  • IGrouping<out TKey, out TValue>

반공변성을 지원하는 제네릭 인터페이스

  • IComparer<in T>
  • IComparable<in T>
  • IComparer<in T>



📍 List<T> 메서드

  • 리스트 객체의 각 원소를 T 형으로 변환하여 리스트로 반환할 수 있다.

  • public bool Exists(Predicate<T> match)
    리스트에 있는 모든 원소 중 match 조건을 만족하는 원소가 있는지 여부를 반환한다.

  • Find() : List에서 조건을 만족하는 첫번째 원소를 반환한다.
    FindAll() : List에서 조건을 만족하는 모든 원소를 리스트로 반환한다.
    FindIndex() : List에서 조건을 만족하는 첫번째 인덱스를 반환한다.
    FindLastIndex() : List에서 조건을 만족하는 마지막 원소의 인덱스를 반환한다.
    ForEach()
    TrueForAll() : 리스트의 모든 원소가 조건을 만족하는지 여부를 반환한다.
    Remove()



📍 HashSet<T>

중복 요소를 포함하지 않는 고유한 요소의 정렬되지 않은 컬렉션



📍 yeild 키워드

컬렉션 데이터를 하나씩 리턴할 때 사용한다.

🍀 yield 키워드 예제

  • yield return 은 컬렉션 데이터를 하나씩 리턴할 때 사용한다.
  • yield break 는 리턴을 중지하고 iteration 루프를 빠져나올 때 사용한다.
public class yieldTest
{
	static IEnumerable<int> GetNumber()
    {
    	yield return 10; // 첫번째 루프에서 리턴되는 값
        yield return 20; // 두번째 루프에서 리턴되는 값
        yield return 30; // 세번째 루프에서 리턴되는 값
    }
}

public static void Main(string [] args)
{
	foreach(int num in GetNumber())
    {
    	Console.WriteLine(num);
    }
}

출력 결과 : 10 20 30



📍 IComparable 인터페이스

개인적으로 만든 클래스에 대해서 컬렉션에 추가하고, Sort를 이용해 정렬할 때 인터페이스를 구현해야 한다.
이때 구현해야할 메서드는 CompareTo 메서드이다.

CompareTo 메서드

  • 현 객체가 인자보다 작으면음수
  • 현 객체가 인자와 동일하면0
  • 현 객체가 인자보다 크면양수

🍀 CompareTo 메서드 예제

public int CompareTo(A a) 
{
	if (this.str.CompareTo(a.str) == 0) 
    {
		if (this.num > a.num)
			return 1;
		else if (this.num < a.num)
			return -1;
		else
			return 0;
	}
	else 
    {
		return this.str.CompareTo(a.str);
	}
}

Equals 메서드

  • 두 객체의 내용이 같은지 동등성을 비교한다.
  • 객체의 내용이 동일하면true
  • 객체의 내용이 동일하지 않으면false
  • Equals를 사용할 때는 연산자 오버라이딩을 해야 한다.

0개의 댓글