- 메소드(Method)는 객체지향 프로그래밍 언어에서 사용하는 용어로, C와 C++ 언어에서는 함수(Function)이라 불렀고 파스칼에서는 프로시저(Procedure)라고 불린다. 서브루틴(Subroutine) 또는 서브 프로그램(Subprogram)이라 부르는 언어도 있다.
- 메소드(Method)는 일련의 코드를 하나의 이름 아래 묶은 것이다.
- 메소드를 불러주는 것 만으로도 실행할 수 있다. (메소드를 호출(Call) 한다.)
class 클래스_이름 { 한정자 반환_형식 메소드_이름( 매게변수_목록 ) { // 실행하고자 하는 코드 또는 코드 블록 return 메소드_결과; // 반환_형식과 메소드_결과의 형식이 일치해야 한다. } }
- 메소드가 클래스 안에 선언이 된다. 메소드가 함수, 프로시저, 서브루틴 등과 다른점이 있다면, 이 클래스 안에 존재한단는 것이다.
- C#은 객체지향 프로그래밍 언어이고, 객체지향 프로그래밍에서는 코드 내의 모든 것을 객체로 표현한다.
- 각 객체는 자신만의 속성(데이터)과 기능(메소드)를 갖고 있다.
- 메소드(Method)는 "방법", "방식"이라는 뜻을 갖고 있지만, 객체의 일을 처리하느 방법 또는 방식이라고 생각하면 이해하기 쉽다.
- 메소드(Method)s는 매개변수(Parameter)와 반환 형식(Return Type)를 가진다.
- 호출을 받은 메소드는 매개변수를 이용하여 계산을 수행 후 결과를 호출자에게 반환한다.
- 메소드를 활용하면 코드 길이도 줄고, 가독성도 좋아진다.
- 반환형식이 void이 경우, 메소드들은 자기 할 일만 하고 종료한다.
- static 한정자는 사전적으로 "정적", 움직이지 않는다는 뜻을 갖고 있다. (7장에서 더 자세히 다룰 예정)
class Calculator
{
public static int Plus(int a, int b){
Console.WriteLine("Input : {0}, {1}", a, b);
int result = a + b;
return result;
}
}
//-------------------------------------------//
int x = Calculator.Plus( 3, 4 ); // x = 7
int y = Calculator.Plus( 5, 6 ); // y = 11- return 문은 점프문의 한 종류이다.
- 프로그램의 흐름을 갑자기 호출자에게 돌려 놓는다.
- return 문은 언제든지 메소드 중간에 호출되어 메소드를 종결시키고 프로그램의 흐름을 호출자에게 돌려줄 수 있다.
- 아무것도 반환하지 않을때(void)는 return; 이라고 하여, 아무것도 반환하지 않는다.
- 자기 자신을 호출하는 것을 재귀호출이라 한다.
int Fibonacci( int n ){ if( n < 2 ) return n; else return Fibonacci( n-1 ) + Fibonacci( n-2 ); }
- 메소드를 변수를 담아 호출할때, 메소드 외부로부터 메소드 내부로 데이터를 전달받는 매개체 역할을 할 뿐이지, 매게변수도 근본적으로는 "변수"이다. 메소드에 인수로 넘겨진 변수들이 할당하면 변수가 담고있는 데이터만 복사된다.
- Mainapp.Main() 메소드 안에서 Calculator.Plus()가 실행 되었을때, Plus()에 넘긴 데이터가 참조든 값이든 복사가 이루어진다.
- 이때는 별개의 메모리 공간을 사용한다.
- 이처럼 메소드를 호출할 때 데이터를 복사해서 매게변수에 넘기는 것을 "값에 의한 전달(pass by value)" 라고 한다.
using System; namespace SwapByValue{ class MainApp{ public static void Swap(int a, int b){ int temp = a; b = a; a = temp; } static void Main(string[] args){ int x = 3, y = 4; Console.WriteLine($"x:{x}, y:{y}"); Swap(x, y); Console.WriteLine($"x:{x}, y:{y}"); // 값에 의한 전달은 x, y에 영향이 없다. } } }
x:3, y:4
x:3, y:4
-
값에 의한 전달은 MainApp에 존재하는 변수에 영향을 끼치지 못했다.
-
매게변수를 참조에 의한 전달로 진행하면, 정상적으로 동작하게 된다.
-
C#에서 참조에 의한 매개변수 전달은 ref 키워드로 이루어진다.
-
메소드 선언에 ref 키워드를 매개변수 앞에 붙여준다.
using System; namespace SwapByValue{ class MainApp{ public static void Swap(ref int a, ref int b){ int temp = a; b = a; a = temp; } static void Main(string[] args){ int x = 3, y = 4; Console.WriteLine($"x:{x}, y:{y}"); Swap(ref x, ref y); Console.WriteLine($"x:{x}, y:{y}"); // 값에 의한 전달은 x, y에 영향이 없다. } } }
x:3, y:4
x:4, y:3
- 메소드의 결과를 참조로 반환하는 "참조 반환값(ref return)"에 대해 알아본다.
- ref 한정자를 이용해서 메소드를 선언하고, return 문이 반환하는 변수 앞에도 ref 키워드를 명시한다.
using System; namespace RefReturn{ class Product{ private int price = 100; public ref int GetPrice() { return price; } public void PrintPrice(){ Console.WriteLine($"Price :{price}"); } } class MainApp{ static void Main(string[] args){ Product carrot = new Product(); ref int ref_local_price = ref carrot.GetPrice(); int nor_local_price = carrot.GetPrice(); carrot.PrintPrice(); // 100 Console.WriteLine($"Ref Local Price :{ref_local_price}"); // 100 Console.WriteLine($"Nor Local Price :{nor_local_price}"); // 100 ref_local_price = 200; carrot.PrintPrice(); // 200 Console.WriteLine($"Ref Local Price :{ref_local_price}"); // 200 Console.WriteLine($"Nor Local Price :{nor_local_price}"); // 100 } } }
- 두 개 이상의 결과를 요구하는 특별한 메소드가 존재한다.
void Divide( int a, int b, ref int quotient, ref int remainder){ quotient = a / b; remainder = a % b; } //------------------------------------// int a = 20, b = 3; int c = 0; int d = 0; Divide( a, b, ref c, ref d); Console.WriteLine("quotient: {0}, Reminder {1}", c, d); // 정상작동한다.
- 이러한 경우 안정성을 위해 out 키워드를 이용한다.
- ref 키워드를 이용해서 매개변수를 넘기는 경우, 메소드가 해당 매게변수에 결과를 저장하지 않아도 컴파일러는 아무런 경고를 하지 않는다.
- 반대로 out 키워드는 컴파일러가 에러 메세지를 출력한다.
- 또한 메소드를 호출하는 쪽에서, 초기화하지 않은 지역 변수를 메소드의 out 매개변수로 넘길 수 있다.
- 또한 출력 전용 매게변수는 호출할 때 매개변수 목록 안에서 즉석으로 선언해도 된다.
void Divide( int a, int b, out int quotient, out int remainder){ quotient = a / b; remainder = a % b; } //------------------------------------// int a = 20, b = 3; //int c = 0; int d = 0; Divide( a, b, out int c, out int d); //out c, out d Console.WriteLine("quotient: {0}, Reminder {1}", c, d); // 정상작동한다.
- 하나의 메소드 이름에 여러개의 구현을 올리는 것이다.
- 오버로딩(Overloading)이란 "과적하다"라는 뜻을 지니고 있다.
- 오버로딩 해 놓으면 컴파일러가 메소드 호출 코드에 사용되는 매개변수의 수와 형식을 분석해서 어떤 버전이 호출될지 찾아준다.
- 실행할 메소드의 버전을 찾는 작업이 컴파일 타임에 이루어지므로 성능 저하는 걱정하지 않아도 된다.
- 이를 통해 코드를 일관성 있게 유지해준다.
int Plus(int a, int b){ return a + b; } double Plus(double a, double b){ return a + b; } //---------------------------------// int result1 = Plus(1,2); double result2 = Plus( 3.1, 2.4 );
- 형식은 같으나 매개 변수의 개수만 유연하게 달라질 수 있는 경우에 적합
- params 키워드와 배열을 이용한다.
int Sum( params int[] args ){ int sum = 0; for(int i = 0; i < args.Length; i++) sum += args[i]; return sum; } //-------------------------------// int total = 0; total = Sum( 1, 2 ); total = Sum( 1, 2, 3 ); total = Sum( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
- 메소드를 호출할 때 매개변수 목록 중 어느 매개변수에 데이터를 할당할지 지정하는 것은 "순서"이다.
- C#에서는 또 다른 스타일인 명명된 인수(Named Ardument)를 활용하여, 메소드를 호출할 때 인수의 이름에 근거해서 데이터를 할당할 수 있는 기능이다.
static void PrintProfile( string name, string phone ){ Console.WriteLine("Name :{0}, Phone :{1}", name, phone); } //------------------// PrintProfile(name : "박주형", phone : "010-0000-1111");
- 메소드의 매개변수는 기본 값을 가질 수 있다.
- 매개변수를 특정한 값으로 초기화하듯 메소드를 선언할 수 있다.
- 선택적 인수는 항상 필수로 인수 뒤에 와야 한다.
void MyMethod( int a, int b = 0 ){ Console.WriteLine("{0}, {1}", a, b); } //-------------------------------// MyMethod( 3 ); MyMethod( 3, 2 );
- 로컬 함수(Local Function)는 메소드 안에 선언되고, 선언된 메소드 안에서만 사용되는 특별한 함수이다.
- 클래스의 맴버가 아니기 때문에 메소드가 아니라 함수(Function)이라고 불린다.
class SomeClass {
public void SomeMethod() {
int count = 0;
SomeLocalFunction(1,2);
SomeLocalFunction(3,4);
void SomeLocalFunction( int a, int b){
Console.WriteLine($"count : {++count}");
}
}
}