메소드는 객체지향 프로그래밍 언어에서 사용하는 언어로,C와 C++ 언어에서는 함수라 불렀고 파스칼에서는 프로시저라고 불렀습니다. 혹은 서브루틴이나 서브 프로그램이라고 부르는 언어도 있습니다. 메소드 = (함수,프로시저,서브루틴,서브 프로그램)
메소드는 일련의 코드를 하나의 이름으로 묶은 것입니다. 이렇게 묶은 코드는 메소드의 이름을 불러주는 것만으로 실행할 수 있습니다.
class 클래스_이름
{
한정자 반환_형식 메소드_이름(매개변수_목록)
{
실행하고자 하는 코드1;
실행하고자 하는 코드2;
실행하고자 하는 코드n;
_
return 메소드_결과;
}
}
매개변수()와 인수()
매개변수는 메소드가 호출자에게서 전달받은 값을 받는 변수를 말하고,인수는 매개변수에 넘기는 값을 말합니다.
예를들어,Calculator클래스 안에 선언한 메소드 Plus(int a, int b)에서 int a, int b가 매개변수이고 Calculator.Plus(3,4)에서 3,4는 인수입니다.
static 한정자
static은 사전적으로 "정적"이라는 뜻을 가지고 있습니다. 움직이지 않는다는 뜻입니다. C#에서 static은 메소드나 필드가 클래스의 인스턴스가 아닌 클래스 자체에 소속되도록 지정하는 한정자 입니다. 한정자를 static으로 수식하면 클래스 인스턴스를 만들지 않고도 해당 메소드를 호출할 수 있습니다.
return 문은 점프문의 한 종류입니다. return문은 언제든지 메소드 중간에 호출되어 메소드를 종결시키고 프로그램의 흐름을 호출자에게 돌려줄수있습니다.
int Fibonacci(int n)
{
if(n<2)
return n;
else
return Fibonacci(n-1) + Fibonacci(n-2);
}
메소드가 반환할 것이 아무것도 없는 경우, 즉 반환 형식이 void형식인 경우에도 return문을 사용할수 있습니다.
void PrintProfile(string name, string phone)
{
if (name == "")
{
Console.WriteLine("이름을 입력해주세요");
return; //함수를 빠져나가게 할 수단으로 씀
}
Console.WriteLine($"Name:{name},Phone:{phone}")
}
재귀호출
메소드가 자기 자신을 스스로 호출하는 것을 일컬어 재귀 호출이라고합니다. 조금전의 Fibonacci()메소드가 조건에 따라 또 다시 자신을 호출했습니다 재귀 호출은 코드를 단순하게 할수있는 반면에 성능에는 나쁜 영향을 미치기 때문에 조심하게 사용해야합니다.
매개변수는 메소드 외부로부터 내부로 대이터를 전달받은 매개체 역활을 할뿐이지,매개변수도 근본적으로는 "변수"입니다. 한 변수를 또 다른 변수에 할당하면 변수가 담고 있는 데이터만 복사될 뿐입니다. 그 데이터가 값이든 참조이든 간에 말입니다.
public static void Swap(int a, int b)
{
int temp = b;
b = a;
a = temp;
}
static void Main(string[] args)
{
int x = 3;
int y = 4;
Swap(x,y);
}
이 메소드를 실행하면 서로의 값이 제대로 뒤바뀌어 4와 3이 되어있을까요? 아닙니다. 매개변수는 복사만 수행하기 때문에 a,b에 x,y의 값이 복사되어봤자 함수 밖에있는 x,y에 영향이 전혀 없기 때문입니다. 이런 전달 방식을 값에 의한 전달(pass by value)이라고 합니다
값에 의한 전달이 매개변수가 변수나 상수로 부터 값을 복사하는 방식이라면, 참조에 의한 전달은 매개변수가 메소드에 넘겨진 원본 변수를 직접 참조합니다.
참조에 의한 전달방식은 ref 키워드를 사용합니다
public static void Swap(ref int a, ref int b)
{
int temp = b;
b = a;
a = temp;
}
static void Main(string[] args)
{
int x = 3;
int y = 4;
Swap(ref x,ref y);
}

Swap()메소드가 참조로 매개변수를 전달할때의 과정입니다. 스택에 있는 x,y를 직접 참조합니다.
메소드의 결과를 참조하는 참조 반환값(ref return)입니다. 참조반환값을 이용하면 메소드의 호출자로 하여금 반환받은 결과를 참조로 다룰 수 있도록 합니다.
ref 한정자를 이용해서 메소드를 선언하고, return문이 반환하는 변수 앞에도 ref키워드를 명시해야 합니다.
class SomClass
{
int SomeValue = 10;
public ref int SomeMethod()
{
//실행할 코드
return ref SomeValue;
}
}
SomeValue()메소드가 반환하는 결과를 호출자가 참조로 넘겨 받고 싶다면 다음과 같이 결과를 담는 지역변수와 호출할 메소드의 이름에 ref 키워드를 위치 시켜야합니다. 이렇게 참조로 반환받은 결과를 담는 지역변수를 참조 지역변수(ref local)라고 합니다.
SomeClass obj = new SomeClass();
ref int result = ref obj.SomeMethod(); //result는 참조 지역변수 입니다.
참고로 SomeMethod()는 참조로 반환 하도록 구현됐지만, 호출자가 특별한 키워드를 사용하지 않는한 값으로 반환하는 평범한 메소드로 동작됩니다.
SomeClass obj = new SomeClass();
int result = obj.SomeMethod(); //값으로 반환받고자 할때는 여느 때와 다름없이 사용하면 됩니다.
아래는 참조 반환값 예제 코드입니다.
class Product
{
private int price = 100;
public ref int GetPrice()
{
return ref price;
}
}
class MainApp
{
static void Main(string[] args)
{
Product carrot = new Product();
ref int set_local_price = ref carrot.GetPrice(); // set_local_price의 값을 변경하면 carrot.price의 내용도 바뀝니다.
int get_local_price = carrot.GetPrice();
set_local_price = 200;
}
}
대개의 메소드의 결과는 한개면 충분합니다. 하지만 두 개 이상의 결과를 요구하는 메소드들도 있습니다.
예를 들어 나눗셈을 구현할 때는 제수와 피제수를 매개변수로 넘겨받고 결과는 몫과 나머지로 반환해야 할 때가 있습니다. 그럴떈 다음과 같이 ref 키워드를 통해 메소드를 구현하면 두개의 반환할 수 있습니다.
void Divide (int a, int b, ref int quotient,ref int remainder)
{
quotient = a / b;
remainder = a % b;
}
//사용
int A_quotient = 0;
int A_remainder = 0;
Divider(20,5,ref A_quotient,ref A_remainder);
그런데 C#은 더 안전한 방법으로 같은 일을 하게 만들수있습니다.
out 키워드를 이용한 "출력 전용 매개변수"가 그것입니다.
out 키워드를 사용하는 이유는 반드시 결과를 출력하게하기 위해서입니다. out 키워드를 사용하여 매개변수를 넘길때는 메소드가 해당 매개변수에 결과를 저장하지 않으면 컴파일러가 에러 메시지를 출렵합니다.
한편,메소드 호출하는 쪽에서는 초기화 하지 않은 지역변수를 out 매개 변수로 넘길 수 있습니다. 컴파일러가 호출당하는 메소드에서 그 지역 변수를 할당할 것을 보장하기 때문입니다.
런타임에 발생하는 버그는 컴파일 타임에 발생하는 버그보다 훨씬 잡기가 어렵기 때문에 out 매개변수 같은 안전장치를 사용합니다.
void Divide (int a, int b, out int quotient, out remainder)
{
quotient = a / b;
remainder = a % b;
}
//사용
int a = 20;
int b = 3;
//int c;
//int a;
Divide(a,b,out int c,out int d); //초기화 하지 않은 지역변수를 매개변수로 씀
Console.WriteLine($"Quotient : {c}, Remainder : {d}");
오버로딩이란 "과적하다"라는 뜻을 갖고 있습니다. 메소드 오버로딩은 하나의 메소드 이름에 여러개의 구현을 올리는 것을 뜻합니다.
메소드 오버로딩은 이름에 대한 고민을 줄여주는 동시에 코드를 일관성있게 유지해줍니다.
int Plus(int a,int b)
{
return a+b;
}
double Plus(double a, double b)
{
return a+b;
}
프로그래밍을 하다보면 그저 인수의 개수가 다르다는 이유만으로 똑같은 메소드를 여러가지 버전으로 오버로딩 하고 싶을때가 있습니다. 이런 경우 "가변 개수의 인수"라는 기능을 사용할수있습니다.
가변 개수의 인수란, 그 개수가 유연하게 변할수있는 인수를 말합니다.
//가변 개수의 인수 작성
int Sum(Params int[] args)
{
int sum = 0;
foreach(i in args)
{
sum += i;
}
return sum;
}
//사용
int total = 0;
int total2 = 0;
int total3 = 0;
total = Sum(1,2);
total2 = Sum(1,2,3,4,5,6);
total3 = Sum(1,2,3,4,5,6,7,8,9);
가변 개수의 인수는 같은 형식만 유연하게 개수를 늘릴수 있으니 주의 할것
메소드를 호출할 때 매개변수 목록중 어느 매개변수에 데이터를 할당할지 지정하는 것은 "순서"입니다. 명명된인수는 메소드를 호출할 때 순서가 아닌 인수의 이름에 근거해서 데이터를 할당할 수 있는 기능입니다.
명명된 인수는 그저 메소드를 호출할때 인수의 이름뒤에 콜론(:)을 붙인뒤에 할당할 데이터를 넣어주면 됩니다. 코드의 가독성이 훨씬 좋아지는 까닭에 사용합니다.
//명명된 인수 작성
static void PrintProfile(string name, string phone)
{
Console.WriteLine($"Name:{name},Phone:{phone}");
}
//사용
static void Main(string[] args)
{
PrintProfile(name:"박찬호", phone:"010-1234-1234"); //명명된 인수 사용하기
}
메소드의 매개변수는 기본값을 가질수 있습니다.
예를 들면 다음과 같이 매개변수를 특정값으로 초기화 하듯 메소드를 선언할수 있다는 겁니다.
void MyMethod(int a, int b = 0)
{
Console.WriteLine($"a : {a}, b : {b}");
}
//사용
MyMethod(3); //b의 기본값은 0
MyMethod(3,4); //a=3,b=4
선택적인수는 메소드의 사용자에게 신경쓰고 싶지않은 인수를 염두에 두지않도록 편의를 제공하지만, 모호함이라는 스트레스도 같이 줍니다. 이러한 모호함은 매개변수의 수가 많거나,오버로딩이 있는 메소드라면 더욱 심해집니다. 따라서 선택적 매개변수를 사용할때는 이점을 꼭 정책적으로 명확히 정하고 프로그래밍 해야합니다.
로컬 함수는 메소드 안에서 선언되고, 선언된 메소드 안에서만 사용하는 특별한 함수입니다. 클래스의 멤버가 아니기 때문에 메소드가 아니라 함수라고 부릅니다. 로컬함수는 자신이 존재하는 지역에 선언되어있는 변수를 사용할수있습니다.
로컬함수는 메소드 밖에서는 다시 쓸일없는 반복적인 작업을 하나의 이름 아래 묶어놓는 데 제격입니다.
class SomClass
{
public void SomMethod()
{
int count = 0;
SomeLocalFunction(1,2); //로컬함수 사용
SomeLocalFunction(3,4);
void SomeLocalFunction(int a, int b)
{
//지역변수 count사용가능
Console.WriteLine($"count : {++count}");
}
}
}