ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 9장. 매개변수
    CLR Via C# 2022. 1. 30. 02:34

    선택적 매개변수와 기본값이 설정된 매개변수

    매개변수 설정시 기본값을 설정할 수 있고, 매개변수를 선택적으로 전달할 수 있다.

    private void M(int num,int x = 9,string s ="A", Guid guid = new Guid()){ ... }
    // 기본값이 설정된 매개변수는 기본값이 설정되지 않은 매개변수 보다 오른쪽에 위치해야한다.
    public static void Main(){
        M(5, s:"BB");    // num은 기본값이 없고 5를 전달, x는 기본값 9 
                        // s는 BB를 전달.guid는 new Guid 전달 명명된 매개변수사용은 오른쪽에 위치해야함
    }

    암시적으로 타입화된 지역 변수

    C#은 메서드 내의 지역 변수의 타입을 초기화 표현식으로부터 자동으로 유추할 수 있는 var를 제공한다.

    private static void hi(){
        var name = "Lim";    // System.String을 표시한다.
        // var n = null;    // 오류! var에는 null을 대입할 수 없다.
                            // null은 참조타입과 값타입(Nullable<T>) 두개 중 유추가 불가능
        var numbers = new int[] { 1, 2, 3, 4};    // System.int[]를 표시한다.
    }

    메서드에 참조로 매개변수 전달

    C#에서는 outref 키워드를 지정해서 메서드에 참조로 매개변수 전달을 한다. 함수 호출시 명시적으로 키워드를 붙여야한다. out과 ref는 참조로 전달한다는 의미로 메타데이터 상으로는 차이가 없다.(그래서 오버로딩 안됨)

    out : out 매개변수는 쓰기 전용이며 초기화되지 않은 상태로 전달 가능하다. 메서드 내에서 초기화를 해줘야 한다.

    ref : ref 매개변수는 읽기/쓰기가 가능하다. 메서드로 전달되기 전 매개변수는 초기화가 되어야 한다.

    public static void Main(){
        int x;
        GetVal(out x);
        int y = 10;
        AddVal(ref y);
    }
    
    private static void GetVal(out int v){
        v = 10;
    }
    private static void AddVal(ref int v){
        v += 10;
    }
    • 참조 전달 방식은 전달되는 변수의 타입의 메서드가 기대하는 타입과 동일해야 한다. 만약 void M(ref Object a){}인 메소드에 String을 전달하면 캐스팅은 일어나지 않고 오류가 발생한다. 이를 피하기 위해서 제네릭를 사용할 수 있다.
    public static void Swap<T>(ref T a, ref T b){
        T t = b;
        b = a;
        a = t;
    }

    메서드에 가변 매개변수 전달하기

    배열 매개변수에 params키워드를 붙여서 사용한다. 어떤 타입이든 가능하며 1차원 배열이어야만 한다.

    static Int32 Add(params Int32[] values){
        Int32 sum = 0;
        if(values != null){
            for(Int32 x = 0; x < values.Length; x++)
                sum += values[x];
        }
        return sum;
    }

    호출은 다음 같이 한다.

    public static void Main(){
        //Console.WriteLine(Add(new Int32[] { 1, 2, 3, 5, 6 }));    // params가 없을 시
        Console.WriteLine(Add(1, 2, 3, 4, 5));
    }

    params 키워드를 이용하면 매개변수에 System.ParamArrayAtrribute 사용자 정의 특성을 붙인다.

    일단 이러한 메서드를 만나면 ParamArrayAtrribute 특성이 없는 메서드부터 찾고 없으면 특성이 부여된 메서드를 찾는다. 만약 특성이 부여된 메서드를 찾아내면, 배열을 만들고 매개변수들을 배열에 추가한 후, 이 베열을 매개변수로 전달하도록 IL코드를 생성한다.

    • 사실 가변 매개변수를 전달하는 경우 null을 전달하지 않는 한 성능 저하기 있을 수 있다. (힙에 배열 객체를 할당해야 한다. 결국 가비지 컬렉션의 대상이 된다.) 그래서 되도록이면 자주 사용될 가능성이 있는 패턴은 미리 오버로드의 형태로 구현하는 것이 좋다.

    매개변수 타입과 반환 타입에 대한 지침

    메서드의 매개변수 타입을 정의할 때에는 가능한 가장 상위추상화된 타입이나 인터페이스 타입을 사용하는 것이 좋다. 예를 들어, List, ICollection, IList 같이 구체화된 타입 보다는 IEnumerable 인터페이스 같은 추상적인 타입이 바람직하다. 이렇게 하는 이유는 재사용에 있어서 유용하기 때문이다.

    반면에, 메서드의 반환 타입을 정의할 때에는 가능한 구체적인 타입으로 정의하는 것이 좋다.(추상적이지 않은 것) 이는 메서드를 호출한 측에서는 반환된 객체의 기능을 사용할 때 의도하는 기능의 의미가 넓어지면 정확한 기능을 특정하기가 힘들어진다.

    상수화

    C++ 언어와 같은 비관리 언어에서 인스턴스 메서드나 매개변수에 대해 const 키워드를 사용해 수정할 수 없도록 한다. 사실 이는 역캐스팅이나 실제 주소를 얻어와서 얼마든지 객체나 매개변수의 값과 상태를 자유롭게 변경할 수 있다.

    그렇다면 CLR(C#도 마찬가지)에서는 객체나 매개변수가 변경되지 않았음을 매 순간 검증해야하는데 이는 성능에 과부하가 심하다. 그러한 이유로 CLR은 객체나 매개변수에 대한 상수화를 지원하지 않는다.

    'CLR Via C#' 카테고리의 다른 글

    11장. 이벤트  (0) 2022.02.07
    10장. 속성  (0) 2022.02.02
    8장. 메서드  (0) 2022.01.25
    7장. 상수와 필드  (0) 2022.01.23
    6장. 타입과 멤버의 기본  (0) 2022.01.21
Designed by Tistory.