출처: http://chovo.net/tag/c%23


레퍼런스 타입의 변수는 파라미터로 넘겨진 레퍼런스를 통해 직접 해당 오브젝트의 내용을 변경할 수 있다. 하지만, 밸류 타입은 파라미터가 함수 안의 변수로 선언되고 값이 복사되어 들어가기 때문에 함수 내부에서 값을 변경하면 함수 안의 파라미터 변수의 값만 변하고, 함수 호출이 끝나면 사라져 버리기 때문에 원래 변수의 값은 그대로 남게 된다. 즉, ref와 out은 파라미터로 넘겨진 밸류 탑입의 값을 변경할 때 사용한다.
이것은 어찌보면 C/C++ 에서 함수에 파라미터로 넘겨줄때 해당 변수의 주소값을 넘겨주어서 변수의 값을 변경하는 것과 비슷한 방식이라 할 수 있다. C#에서도 포인터가 있지만 포인터에 대해서는 나중에 살펴보도록하고, 우선 refout에 대해 알아보도록 하자.

아래 소스에서는 Main에서 Point 클래스를 이용하여 myPoint 라는 이름의 객체를 생성하고, 이 인스턴스의 맵버함수인 GetPoint를 호출하여 x와 y의 값을 얻어오는 코드이다.

less..

class Program
{
        static void Main(string[] args)
        {
            Point myPoint = new Point(10, 15);
            int x;
            int y;

            myPoint.GetPoint(ref x, ref y);

            Console.WriteLine("myPoint({0}, {1})", x, y);
        }
}

class Point
{
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public void GetPoint(ref int x, ref int y)
        {
            x = this.x;
            y = this.y;
        }
        int x;
        int y;
}

less..


우선 이 코드를 컴파일하면 컴파일러는 할당되지 않은 지역 변수를 사용했다는 메시지와 함께 에러를 발생한다. 이런 상황에서 두 가지 방법을 사용할 수 있는데, 첫 번째는 변수를 선언할 때 초기화를 하는 것이다. 아래는 변경된 예제이다.

less..

class Program
{
        static void Main(string[] args)
        {
            Point myPoint = new Point(10, 15);
            int x=0;
            int y=0;


            myPoint.GetPoint(ref x, ref y);

            Console.WriteLine("myPoint({0}, {1})", x, y);
        }
}

class Point
{
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public void GetPoint(ref int x, ref int y)
        {
            x = this.x;
            y = this.y;
        }
        int x;
        int y;
}

less..

이와같이 파라미터로 넘겨지는 변수 x, y에 대해서 변수 선언시 초기화를 해주면 코드는 정상정으로 컴파일 되며 동작 역시 잘 돌아간다. 하지만, 0으로 초기화된 다음에 GetPoint() 함수에서 값이 다시 쓰여진다. 이것은 무언가 조금 지저분하다고나할까, 의미없는 동작을 한다고나할까...아무튼 뭔가 마음에 들지 않는다.
C#에서는 ref 파라미터 대신에 out 파라미터를 사용해서 GetPoint() 함수의 정의를 바꿀 수 있는 옵션을 제공한다. 아래 코드는 ref 대신 out을 사용한 예제이다.

less..

class Program
{
        static void Main(string[] args)
        {
            Point myPoint = new Point(10, 15);
            int x;
            int y;


            myPoint.GetPoint(out x, out y);

            Console.WriteLine("myPoint({0}, {1})", x, y);
        }
}

class Point
{
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        public void GetPoint(out int x, out int y)
        {
            x = this.x;
            y = this.y;
        }
        int x;
        int y;
}

less..

out 파라미터는 초기화되지 않은 변수를 넘겨서 사용할 수 있다는 점을 빼면 ref 파라미터와 똑같다. 따라서, ref 보다는 out을 이용해서 함수를 호출하는 것이 좋다. .Net 언어라는 관점에서 보면, ref와 out 파라미터는 아무런 차이가 없다. C# 프로그램에서 out 파라미터로 함수를 호출하더라도, 다른 언어에서 보기에는 ref 파라미터를 이용한 것과 같다.

AND