본문 바로가기
전공/C# 프로그래밍

6강. 메소드 (Method)

by 임 낭 만 2023. 4. 17.

메소드(Method)란?

  • C언어의 함수와 같은 개념이고, C#에서는 클래스 안에 존재
  • 매개변수와 반환 형식을 가짐
    • 매개변수: 메소드 안에서 사용되어지는 변수
    • 반환 형식: 메소드 수행 결과 값의 데이터형, 수행 결과는 메소드 호출자에게 반환
    • 반환할 수행결과가 없는 메소드 경우 반환형식으로 “void” 이용

클래스 내부에 선언. (메소드 선언 필수 요소 : 반환 형식, 메소드 이름, 매개 변수 목록). 결과를 반환할 때 return문 사용

메소드 사용 예제

  • 메소드 호출 시 일어나는 프로그램 흐름 (예제코드 참고)
    • (1) Calculator 객체의 Plus() 메소드 호출, 3과 4에 해당하는 인수를 넘김
    • (2) 프로그램 흐름이 Plus() 메소드로 이동 후, 메소드 안에 코드를 차례로 수행
    • (3) 메소드 블록 끝 도달 또는 return 문을 만났을 경우 메소드 종결
    • (4) Plus() 메소드 호출한 곳으로 흐름이 되돌아 오고 이후 코드를 계속 실행

일련의 코드를 하나의 이름 아래 묶은 것 : 메소드, 함수(Function), 프로시저 (Procedure), 서브루틴, 서브 프로그램

한정자 : 메소드의 속성을 수식하는 한정자를 둘 수 있음

매개 변수 목록 : 메소드에 입력하는 매개 변수의 목록임

메소드 결과의 데이터 형식은 메소드의 반환 형식과 일치해야 함

메소드 호출 : 메소드의 이름을 불러 주는 것만으로 실행

using System;

namespace Method
{
    class Calculator
    {
        public int Plus (int a, int b)
        {            
            return a + b;
        }

        public int Minus(int a, int b)
        {            
            return a - b;
        }
    }

    class MainApp
    {
        static void Main(string[] args)
        {
            Calculator Calc = new Calculator();

            int x = Calc.Plus(3, 4);
            Console.WriteLine($"3 + 4 = {x}");

            int y = Calc.Minus(5, 2);
            Console.WriteLine($"5 - 2 = {y}");            
        }
    }
}


return 문

  • 프로그램의 흐름을 호출자에게로 돌려 놓음
    • 메소드 끝 뿐 아니라 메소드 중간에도 사용하여 메소드 종결 가능
    • 반환 형식이 void 인 경우에도 return 문 사용 가능
  • 재귀 호출
    • 메소드가 자기 자신을 스스로 호출하는 것
    • 코드를 간결하게 작성 할 수 있지만 성능엔 악영향이 될 수 있음

호출자에게 결과를 반환. 점프문의 한 종류. 메소드의 어느 위치에서나 호출 가능

반환 형식과 일치하는 데이터를 반환해야 한다. 메소드가 void 형식인 경우 반환값 없이 사용 가능

using System;

namespace Return
{
    class ReturnTest
    {
        public int Fibonacci(int n)
        {
            if (n < 2)
                return n;
            else
                return Fibonacci(n - 1) + Fibonacci(n - 2);
        }
        public void PrintProfile(string name, string phone)
        {
            if (name == "")
            {
                Console.WriteLine("이름을 입력해주세요.");
                return;
            }
            Console.WriteLine($"Name:{name}, Phone:{phone}");
        }
    }
    class MainApp
    {
        static void Main(string[] args)
        {
            ReturnTest RT = new ReturnTest();
            Console.WriteLine($"10번째 수: {RT.Fibonacci(10)}");

            RT.PrintProfile("", "123-4567");
            RT.PrintProfile("홍길동", "456-1230");
        }
    }
}


값에 의한 매개 변수 전달

  • 메소드에 인수로 넘겨진 값들은 매개변수에 할당됨
    • 한 변수를 또 다른 변수에 할당하면 데이터 값만 복사
    • 예제코드에서 변수 a와 x는 똑같은 데이터를 갖지만 별개의 메모리 공간 사용

  • Swap 메소드
    • 두 정수 입력 값을 매개변수로 전달 받아 변수의 값을 서로 바꿈
    • 매개변수에는 인수 값이 복사되어 전달
    • Main 메소드 안의 x와 y에는 영향이 없음
using System;
using System.Security.Cryptography.X509Certificates;

namespace SwapByValue
{
    class MainApp
    {
        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;
                     
            Console.WriteLine($"x:{x}, y:{y}");
            Swap(x, y);
            Console.WriteLine($"x:{x}, y:{y}");
        }
    }
}


참조에 의한 매개변수 전달

  • 매개변수가 메소드에 넘겨진 원본 변수를 직접 참조
    • 메소드 안에서 매개변수를 수정하면 원본 변수에도 수정이 이뤄짐
    • 메소드를 호출할 때와 메소드를 선언 할 때 매개변수 앞에 ref 키워드를 붙여줌

매개 변수로 직접 원본 변수의 값을 바꾸는 방법

using System;

namespace SwapByRef
{
    class MainApp
    {
        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;

            Console.WriteLine($"x:{x}, y:{y}");
            Swap(ref x, ref y);
            Console.WriteLine($"x:{x}, y:{y}");
        }
    }
}


메소드 결과를 참조로 변환

  • 메소드의 결과를 참조로 반환하는 참조 반환값
    • 메소드 호출자로 하여금 반환 받은 결과를 참조로 다룰 수 있도록 함
    • ref 키워드(한정자)를 이용해서 메소드 선언,
    • return 문이 반환하는 변수 앞에도 ref 키워드 명시
    • 호출자는 결과를 값으로 반환 받을 수 있고, 참조로도 반환 받을 수 있음

ref 키워드로 메소드를 한정함. return 문을 사용할 때 ref 키워드를 반환할 필드나 객체 앞에 붙여줌. 값으로 반환하고자 할 때는 여느 때와 다름없이 메소드를 호출하면 됨.

using System;

namespace RefReturn
{
    class Product
    {
        private int price = 100;

        public ref int GetPrice()
        {
            return ref 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 normal_local_price = carrot.GetPrice();

            carrot.PrintPrice();
            Console.WriteLine($"Ref Local Price : {ref_local_price}");
            Console.WriteLine($"Normal Local Price :{normal_local_price}");

            ref_local_price = 200;

            carrot.PrintPrice();
            Console.WriteLine($"Ref Local Price : {ref_local_price}");
            Console.WriteLine($"Normal Local Price :{normal_local_price}");
        }
    }
}


출력 전용 매개 변수

출력 전용 매개 변수 : out

  • 메소드에서 수행결과 값을 저장하기 위해 사용되는 매개변수
    • 메소드의 선언부와 호출부에 out 키워드 사용
    • 메소드는 하나 이상의 수행 결과 값을 호출자에게 전달 가능

두 가지 이상의 결과가 필요한 메소드

out와 ref 키워드 사이의 차이점

  • ref 키워드와 달리 out 키워드 사용 시 메소드에서 출력전용 매개변수에 값을 할당하지 않은 경우 컴파일 에러 발생
  • out 키워드를 사용 시 메소드 호출 전에 미리 선언할 필요 없음
using System;

namespace UsingOut
{
    class MainApp
    {
        static void Divide(int a, int b, out int quotient, out int remainder)
        {
            quotient = a / b;
            remainder = a % b;
        }

        static void Main(string[] args)
        {
            int a = 20;
            int b = 3;
            Divide(a, b, out int c, out int d);
            Console.WriteLine($"a:{a}, b:{b}, a/b:{c}, a%b:{d}");            
        }
    }
}

using System;

namespace UsingRef
{
    class MainApp
    {
        static void Divide(int a, int b, ref int quotient, ref int remainder)
        {
            quotient = a / b;
            remainder = a % b;
        }

        static void Main(string[] args)
        {
            int a = 20;
            int b = 3;
            int c=0, d=0;
            Divide(a, b, ref c, ref d);
            Console.WriteLine($"a:{a}, b:{b}, a/b:{c}, a%b:{d}");
        }
    }
}


메소드 오버로딩 (Overloading)

  • 같은 이름을 사용하는 여러 개의 메소드를 하나의 클래스 안에 구현
    • 컴파일러는 매개변수의 수와 형식을 분석해 어떤 버전의 메소드 호출인지 확인
    • “Console.WriteLine()” 메소드는 총 18 버전을 오버로딩

하나의 메소드 이름에 여러 개의 구현을 올리는 것

using System;

namespace Overloading
{
    class MainApp
    {
        static int Plus(int a, int b)
        {
            return a + b;
        }

        static int Plus(int a, int b, int c)
        {
            return a + b + c;
        }

        static double Plus(double a, double b)
        {
            return a + b;
        }

        static double Plus(int a, double b)
        {
            return a + b;
        }

        static void Main(string[] args)
        {
            Console.WriteLine(Plus(1,2));
            Console.WriteLine(Plus(1, 2, 3));
            Console.WriteLine(Plus(1.0, 2.4));
            Console.WriteLine(Plus(1, 2.4));
        }
    }
}


매개 변수 (인수)

가변 개수의 인수 (가변길이 매개 변수)

  • 데이터형이 같은 인수의 개수를 유연하게 사용하도록 메소드 정의
    • params 키워드와 배열을 이용해 선언
    • 매개변수의 개수가 유한한 경우는 오버로딩 사용

형식은 같으나 매개 변수의 개수만 유연하게 달라질 수 있는 경우에 적용

using System;

namespace UsingParams
{
    class MainApp
    {
        static int Sum(params int[] args)
        {
            Console.Write("Summing... ");
            int sum = 0;
            for (int i = 0; i < args.Length; i++)
            {
                if (i > 0)
                    Console.Write(", ");
                Console.Write(args[i]);

                sum += args[i];
            }
            Console.WriteLine();

            return sum;
        }
        static void Main(string[] args)
        {            
            Console.WriteLine($"Sum : {Sum(1, 2)}");            
            Console.WriteLine($"Sum : {Sum(1, 2, 3)}");            
            Console.WriteLine($"Sum : {Sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)}");
        }
    }
}

명명된 인수 (명명된 매개 변수)

  • 메소드를 호출할 때 인수의 이름에 근거해서 데이터를 할당
    • 메소드 선언은 수정 없이 그대로 사용
    • 메소드 호출할 때만 인수의 이름 뒤에 콜론(:)을 붙인 뒤 할당할 데이터를 넣어 줌
    • 인수가 많아 어느 매개변수인지 분간이 어려운 경우 명명된 인수 활용

매개 변수 이름 : 값 / 메소드 호출 시 매개 변수의 이름을 명시하여 매개 변수에 데이터를 바인드하는 기능.

using System;

namespace NamedParameter
{
    class Program
    {
        static void PrintProfile(string name, string phone)
        {
            Console.WriteLine("Name: {0}, Phone: {1}", name, phone);
        }
        static void Main(string[] args)
        {
            // 명명된 인수 사용 시 인수의 순서는 상관없음
            PrintProfile(phone: "010-123-1234", name: "박찬호");
            PrintProfile(name: "박지성", phone: "010-111-1111");
            PrintProfile("박세리", "010-222-2222");
            PrintProfile("김연아", phone: "010-333-3333");            
        }
    }
}

선택적 인수 (선택적 매개 변수)

  • 메소드의 매개변수는 기본값을 가질 수 있음
    • 기본값을 가진 매개변수는 메소드를 호출할 때 해당 인수를 생략
  • 선택적 인수 (Optional Argument)
    • 기본값을 가진 매개변수는 인수를 생략할지 선택할 수 있음
    • 선택적 인수는 항상 필수 인수 뒤에 위치
  • 메소드의 매개변수가 많을 경우,
    • 메소드 호출 코드를 보고 어느 매개변수에 인수를 할당하는지 분간이 어려움
    • 명명된 인수를 활용
  • 메소드 오버로딩과 함께 사용 시 혼란을 야기
    • 개발자가 분명하게 오버로딩을 사용할지 선택적 인수를 사용할지 결정 필요

메소드 선언시 매개 변수에 기본 값을 할당.

호출자가 인수를 입력하지 않는 경우 메소드는 기본값이 할당된 매개변수 사용. 호출자는 해당 매개 변수에 대한 인수 입력 여부 선택이 가능해짐

필요에 따라 데이터를 할당하거나 할당하지 않을 자유.

using System;

namespace OptionalParameter
{
    class MainApp
    {
        static void MyMethod_0(int a = 0)
        {
            Console.WriteLine("{0}", a);
        }

        static void MyMethod_1(int a, int b = 0)
        {
            Console.WriteLine("{0}, {1}", a, b);
        }

        static void MyMethod_2(int a, int b, int c = 10, int d = 20)
        {
            Console.WriteLine("{0}, {1}, {2}, {3}", a, b, c, d);
        }

        static void PrintProfile(string name, string phone = "")
        {
            Console.WriteLine($"Name:{name}, Phone:{phone}");
        }

        static void Main(string[] args)
        {
            MyMethod_1(3);
            MyMethod_1(3, 4);

            PrintProfile("중근");
            PrintProfile("관순", "010-555-5555");
            PrintProfile(name: "봉길");
            PrintProfile(name: "동주", phone: "010-777-7777");            
        }
    }
}


로컬 함수 (Local Function)

  • 메소드 안에서 선언되고 선언된 메소드 안에서만 사용되는 함수
    • 선언 방법은 메소드와 동일
    • 로컬 함수는 자신이 속한 메소드의 지역 변수를 사용할 수 있음

메소드 내에 선언하고, 그 안에서만 사용하는 특별한 함수. 클래스의 멤버가 아니라서 함수라고 명명. 자신이 존재하는 지역에 선언된 변수 사용. 메소드 밖에서는 다시 쓸 일 없는 반복적인 작업을 하나의 이름 아래 묶어 놓는데 제격

using System;

namespace LocalFunction
{
    class SomeClass
    {        
        public void SomeMethod()        // 메소드 선언
        {
            int count = 0;
            SomeLocalFunction(1,2);     // 로컬 함수 호출
            SomeLocalFunction(3, 4);

            void SomeLocalFunction(int a, int b)    // 로컬 함수 선언
            {            
                Console.WriteLine($"count : {++count}");    // 지역 변수 count 사용
                Console.WriteLine($"a + b : {a + b}");               
            }
        }
    }
    
    class MainApp
    {
        static string ToLowerString(string input)
        {
            var arr = input.ToCharArray();            
            for (int i=0; i<arr.Length; i++)
            {
                arr[i] = ToLowerChar(i);
            }    

            char ToLowerChar(int i) // 로컬 함수 선언
            {                
                if (arr[i] < 65 || arr[i] > 90) // A ~ Z의 ASCII 값 : 65 ~ 90
                    return arr[i];
                else    // a ~ z의 ASCII 값 : 97 ~ 122
                    return (char)(arr[i] + 32); // 지역변수 arr 사용
            }

            return new string(arr);
        }

        static void Main(string[] args)
        {
            SomeClass SC = new SomeClass();            
            SC.SomeMethod();

            Console.WriteLine(ToLowerString("Hello!"));
            Console.WriteLine(ToLowerString("Good Morning."));
            Console.WriteLine(ToLowerString("Goodbye."));
        }
    }
}

댓글