C#

C# 고급 문법 및 기능

bugmin 2024. 4. 25. 09:09

제네릭

 

코드를 하나만 짜놓고 다양한 자료형을 사용할 수 있게 해주어 재사용성을 높일 수 있음

<T> 의 키워드를 사용한다.

 

선언 시점이 아닌 사용시점에 자료형이 결정된다.

 

사용시에는 <T> 대신에 구체적인 자료형을 넣어줘야 한다.

 

class Stack<T>
{
    private T[] elements;
    private int top;
    
    public Stack()
    {
        elements = new T[100];
        top = 0;
    }
    
    public void Push(T item)
    {
    	elements[top++] = item;
    }
    
    public T Pop()
    {
        return elements[--top];
    }
}

Stack<int> intStack = new Stack<int>();
intStack.Push(1);
intStack.Push(2);
intStack.Push(3);
Console.WriteLine(intStack.Pop());

 

Stack은 선입후출임, 이해를 위해 스택을 직접 구현하고 제네릭을 알아가보자

 

1, 2, 3을 순서대로 Push 해준다. 스택에 짜인 메커니즘을 좀 살펴보면

 

 

3까지 push하면 이러한 상태가 된다. push를 할때는 먼저 넣어주고 top 값을 늘려야 하니 elements[top++]가 된다.

 

저기서 pop을 통해 마지막에 들어온 애를 꺼낸다하면

elements[2] 에 접근해야한다. 이는 top 값에서 1을 뺀 값이다. 고로 return elements[--top] 이 되는 것이다.

 

제네릭을 사용하기 위해 클래스 이름에 <T>키워드를 사용했고 제네릭으로 배열을 선언했기에 해당 항목을 사용하려면 꺽쇠 안에 사용하고자 하는 자료형을 넣어주면 된다.

 

여기선 Stack<int> 로 선언했기 때문에 int 로 이루어진 스택을 사용하는 모습이다.

 

두개 이상의 제네릭

 

T1, T2 로 선언해 사용하였다. (꼭 T가 아니여도 되지만 관습같은 것)

 

class Pair<T1, T2> 
{ 
    public T1 First { get; set; }
    public T2 Second { get; set; }
    
    public Pair(T1 first, T2 second) 
    {
    	First = first;
        Second = second
    }
}

Pair<int, string> pair1 = new Pair<int, string>(1, "One");

 

사용 예제

 

딕셔너리서 본 형태임

 

out 과 ref

 

매개변수로 전달하게 되면 반환 값으로 받던 값을 매개변수에 직접적으로 받아 올 수 있다.

 

매개변수를 수정해 원래 값에 영향을 주기에 주의해야한다.

// out 키워드 사용 예시
static void Divide(int a, int b, out int quotient, out int remainder)
{
    quotient = a / b;
    remainder = a % b;
}

// ref 키워드 사용 예시
static void Swap(ref int a, ref int b)
{
    int temp = a;
    a = b;
    b = temp;
}

static void Main(string[] args)
{
    int quotient, remainder;
    Divide(7, 3, out quotient, out remainder);
    Console.WriteLine($"{quotient}, {remainder}");
    
    int x = 1, y = 2;
    Swap(ref x, ref y);
    Console.WriteLine($"{x}, {y}");
}

 

out 인자를 쓰면 매개변수로 전달해준 값이 복사만 되어 전달되는게 아니라 포인터처럼 주소가 전달되어 해당 변수에 직접적으로 수정을 가한다. out 인자가 있는 메서드 내에서 out 매개변수에 값을 대입을 하지 않으면 에러가 나기 때문에 out으로 매개변수를 제공할 때는 해당 변수가 값을 무조건 할당받는구나를 알 수가 있음

 

반면 ref는 비슷하게 가져다 쓰긴 하지만 대입을 하지 않는다고 에러가 나지는 않는다.

ref로 제공할 때는 값이 바뀔 수도 안바뀔 수도 있는 것이다.

 

결국 두 경우 다 참조 형태가 아닌 값 형태의 애들도 매개변수로 전달 시에 직접적으로 값을 받을 수 있게 참조를 제공해주는 장치이다.

다만 out으로 전달된 매개변수는 메서드 내에서 값을 무조건 할당받는다 생각하면 되고 ref의 경우엔 값의 변화가 없을 수도 있는 것이다.

 

값에 대한 복사 없이 메서드 내에서 직접 접근을 하니 빠르기는 하다. 큰 구조체들이 복사가 일어나면 리소스를 많이 쓰게 될텐데 이를 주소로 참조만 하게 되면 성능 상 이점이 생길 수 있다.

 

허나 ref가 많아지면 매개변수들이 늘어나고 가독성적인 면에서 안좋아 질 수가 있다. 또한 out 매개변수는 무조건 값을 할당받기에 이전의 값이 유지가 안될 수가 있으니 다른 데에 저장하고 하면 이또한 코스트가 발생하는 것이다.

 

내 변수를 직접적으로 바꾸기에 고민을 해보고 쓰는 것이 좋다.

'C#' 카테고리의 다른 글

5/1 TIL - Delegate, Func, Action, 람다  (2) 2024.05.01
C# 인터페이스와 열거형  (1) 2024.04.26
C# OOP와 클래스  (0) 2024.04.24
C# 연산자와 문자열 처리  (0) 2024.04.23
C# 입출력과 각종 용어들  (0) 2024.04.22