Search

이것이 C#이다: 6장 - 메소드로 코드 간추리기

서론

C#에서 메소드는 코드의 재사용성과 가독성을 높이는 핵심 요소입니다. 이번 포스트에서는 '이것이 C#이다' 책의 6장을 바탕으로, C# 메소드의 고급 기능들을 살펴보겠습니다. 이러한 기능들은 코드를 더욱 효율적이고 유연하게 만들어주며, 특히 복잡한 로직을 다룰 때 큰 도움이 됩니다.

본론

1. 참조에 의한 매개변수 전달

C#에서는 ref 키워드를 사용하여 매개변수를 참조로 전달할 수 있습니다. 이는 메소드 내에서 매개변수의 값을 변경하고, 그 변경사항을 호출자에게 반영하고자 할 때 유용합니다.
static void Swap(ref int a, ref int b) { int temp = a; a = b; b = temp; } int x = 1, y = 2; Swap(ref x, ref y); Console.WriteLine($"x: {x}, y: {y}"); // 출력: x: 2, y: 1
C#
복사
이 기능은 값을 교환하거나, 큰 객체를 복사하지 않고 전달할 때 유용합니다. 하지만 과도한 사용은 코드의 복잡성을 증가시킬 수 있으므로 주의가 필요합니다.

2. 메소드의 결과를 참조로 반환하기

C# 7.0부터는 메소드의 반환값을 참조로 다룰 수 있게 되었습니다. 이는 ref 반환값을 통해 구현됩니다.
public ref int GetLargestElement(int[] numbers) { int indexOfLargest = 0; for (int i = 1; i < numbers.Length; i++) { if (numbers[i] > numbers[indexOfLargest]) { indexOfLargest = i; } } return ref numbers[indexOfLargest]; } int[] numbers = { 1, 2, 3, 4, 5 }; ref int largest = ref GetLargestElement(numbers); largest = 10; // numbers 배열의 값이 직접 변경됩니다. Console.WriteLine(string.Join(", ", numbers)); // 출력: 1, 2, 3, 4, 10
C#
복사
이 기능은 큰 데이터 구조에서 특정 요소를 반환하고 수정해야 할 때 유용합니다. 하지만 참조 반환은 신중하게 사용해야 하며, 반환된 참조의 수명 주기를 고려해야 합니다.

3. 출력 전용 매개변수

out 키워드를 사용하면 메소드에서 여러 값을 반환할 수 있습니다. 이는 특히 메소드가 여러 결과를 생성하는 경우에 유용합니다.
static void DivideWithRemainder(int dividend, int divisor, out int quotient, out int remainder) { quotient = dividend / divisor; remainder = dividend % divisor; } int q, r; DivideWithRemainder(10, 3, out q, out r); Console.WriteLine($"Quotient: {q}, Remainder: {r}"); // 출력: Quotient: 3, Remainder: 1
C#
복사
out 매개변수는 ref와 달리 메소드 내에서 반드시 값을 할당해야 합니다. 이는 API 설계 시 명확성을 제공합니다.

4. 가변 개수의 인수

params 키워드를 사용하면 메소드가 가변 개수의 인수를 받을 수 있습니다. 이는 유연한 API 설계에 매우 유용합니다.
static int Sum(params int[] numbers) { int total = 0; foreach (int num in numbers) { total += num; } return total; } Console.WriteLine(Sum(1, 2, 3)); // 출력: 6 Console.WriteLine(Sum(10, 20, 30, 40)); // 출력: 100
C#
복사
이 기능은 메소드 오버로딩을 줄이고 코드를 더 간결하게 만들 수 있습니다.

5. 명명된 인수

명명된 인수를 사용하면 메소드 호출 시 매개변수의 이름을 명시적으로 지정할 수 있습니다. 이는 코드의 가독성을 크게 향상시킵니다.
static void CreateUser(string name, int age, string email) { // 사용자 생성 로직 } CreateUser(name: "John", age: 30, email: "john@example.com");
C#
복사
이 기능은 특히 많은 매개변수를 가진 메소드를 호출할 때 유용합니다.

6. 선택적 인수

선택적 인수를 사용하면 메소드 호출 시 일부 인수를 생략할 수 있습니다. 이는 기본값을 가진 매개변수를 정의함으로써 구현됩니다.
static void PrintInfo(string name, int age = 30, string country = "Unknown") { Console.WriteLine($"Name: {name}, Age: {age}, Country: {country}"); } PrintInfo("Alice"); // 출력: Name: Alice, Age: 30, Country: Unknown PrintInfo("Bob", 25); // 출력: Name: Bob, Age: 25, Country: Unknown PrintInfo("Charlie", 35, "USA"); // 출력: Name: Charlie, Age: 35, Country: USA
C#
복사
선택적 인수는 메소드의 다양한 사용 시나리오를 단일 메소드로 처리할 수 있게 해줍니다.

7. 로컬 함수

C# 7.0부터 도입된 로컬 함수는 메소드 내부에 정의되는 함수입니다. 이는 코드의 캡슐화와 가독성을 향상시킵니다.
static int Fibonacci(int n) { return Fib(n); int Fib(int number) { if (number <= 2) return 1; return Fib(number - 1) + Fib(number - 2); } } Console.WriteLine(Fibonacci(6)); // 출력: 8
C#
복사
로컬 함수는 외부 함수의 변수에 접근할 수 있어, 클로저와 유사한 기능을 제공합니다.

결론

C# 메소드의 고급 기능들을 탐구하면서, 이 언어의 설계 철학과 강력함을 새롭게 인식하게 되었습니다. ref와 out 키워드는 C#이 메모리 관리와 성능 최적화를 어떻게 균형 있게 다루는지 보여주는 좋은 예시입니다. 이들은 다른 언어의 포인터나 참조 개념을 안전하고 효율적으로 구현한 것으로, C#의 type-safe한 특성을 유지하면서도 필요할 때 저수준의 제어를 가능케 합니다.
로컬 함수의 도입은 C#이 함수형 프로그래밍의 개념을 어떻게 절차적/객체지향적 패러다임과 조화롭게 통합하는지 보여줍니다. 이는 코드의 캡슐화와 재사용성을 높이는 동시에, 클로저와 유사한 기능을 제공함으로써 더 표현력 있는 코드 작성을 가능하게 합니다.

참고 자료

박상현, "이것이 C#이다", 한빛미디어, 2023