개발/C#

.Net Framework Guideline - Member Design-3

huiyu 2021. 8. 30. 17:45

매개 변수 디자인

- 멤버에 필요한 기능을 제공하는 최소 파생 매개 변수(least derived parameter) 형식을 사용한다.
 예를 들어 컬렉션을 열거하고 각 항목을 출력하기 위한 메서드에서는 ArrayList나 IList가 아닌 IEnumerable을 매개 변수로 사용한다.

- 예약된 매개 변수를 사용하지 않는다.
 나중에 새로운 멤버에 대한 추가가 필요한 경우 새 오버로드를 추가한다.

- 포인터, 포인터 배열 또는 다차원 배열을 매개 변수로 사용하는 public method는 사용하지 않는다. 포인터 및 다차원 배열을 제대로 사용이 어려워 대부분 API에서 이러한 형식을 매개 변수로 사용하지 않도록 디자인한다.

- 오버로드 함수 간에 매개 변수 순서가 일치하지 않게 되더라도, by-value 및 ref 변수 다음에 'out 변수를 배치한다.
 out 매개 변수는 추가 return 값으로 확인 가능하며, 이러한 매개 변수를 그룹화 하면 메서드 시그니처를 더 쉽게 이해할 수 있다.

- 멤버를 재정의하거나 인터페이스 멤버를 구현할 때 매개 변수 이름을 일관되게 지정한다. 그렇게 하면 메서드 간의 관계가 더 잘 전달된다.
 

열거형 및 부울 매개 변수중에서 선택(Choosing Between Enum and Boolean Parameters)

 - 멤버에 둘 이상의 bool 매개 변수가 있다면 열거형을 사용한다.
 - 셋 이상의 값이 필요하지 않다고 확신하는 경우에만 bool을 사용한다.
  열거형을 사용하면 나중에 값을 추가할 수 있지만 열거형에 값을 추가할 경우 미치는 영향을 고려해야 한다.
 - 실제로 두 가지 상태 값이며 부울 속성을 초기화하는데만 사용되는 생성자 매개 변수에서는 부울을 사용하는 것이 좋다.

인수 유효성 검사

 - public 멤버, protected 멤버, 명시적으로 구현된 멤버에 전달된 이수의 유효성을 검사한다. 유효성 검사가 실패하는 경우 'System.ArgumentException' 또는 해당 서브클래스 중 하나를 throw한다.
  public 멤버나 protected 멤버 자체에서 실제 유효성 검사를 수행할 필요는 없다. 내부 하위 수준의 private에서 수행할 수 있다. 중요한 점은 최종 사용자에게 노출되는 인수를 확인한다는 것이다.

- null 인수가 전달된 경우 멤버에서 null 인수를 지원하지 않으면 'ArgumentNullException'을 throw한다.

- 열거형 매개 변수의 유효성을 검사한다. 열거형 인수가 열거형에 의해 정의된 멤버 내에 있다고 가정하지 않는다. CLR에서는 값이 열거형에 정의되지 않은 경우에도 정수값을 열거형 값으로 캐스팅 할 수 있다.

- 열거형 범위 확인에 'Enum.IsDefined'를 사용하지 않는다.

- 변경 가능한 인수는 유효성 검사 이후 변경될 수 있음을 인식한다. 보안이 중요한 멤버인 경우라면 복사본을 만든 다음 인수의 유효성을 검사한 후 처리한다.

매개 변수 전달

프레임워크 디자이너 관점에서 매개 변수는 by-value, 'ref' 매개변수, 'out' 매개 변수 세가지 그룹이 존재한다.

by-value 매개 변수를 통해 인수를 전달하면 멤버는 전달된 실제 인수의 복사본을 받는다. 인수가 값 형식인 경우 인수의 복사본은 스택에 배치된다. 인수가 참조 형식이면 참조의 복사본이 스택에 배치된다. 기본적으로 CLR언어는 기본적으로 매개 변수를 값으로 전달한다.

'ref' 매개 변수를 통해 인수를 전달하면 멤버는 전달된 실제 인수에 대한 참조를 받는다. 인수가 값 형식인 경우 인수에 대한 참조가 스택에 배치된다. 인수가 참조 형식이면 참조에 대한 참조가 스택에 배치된다. 'ref' 매개 변수를 사용하면 호출자가 전달한 인수를 멤버가 수정할 수 있다.

'out' 매개 변수는 'ref' 매개 변수와 유사하나 약간의 차이가 있다. 처음에 이 매개 변수는 할당되지 않은 것으로 간주되며, 일부 값이 할당된 다음에야 멤버 본문에서 읽을 수 있다. 또한 멤버에서 반환하기 전에 일부 값을 매개 변수에 할당해야 한다.

- 'out' 또느 'ref' 매개 변수를 사용하지 않는다.
  'out' 또는 'ref' 매개 변수를 사용하려면 포인터 사용 방법을 알고 있어야 하고, 값 형식과 참조 형식이 어떻게 다른지 알고 있어야 하며, 반환 값이 여러 개인 메서드를 처리할 수 있어야 한다. 또한 'out'과 'ref의 차이점도 알아야 한다. 일반 사용자를 대상으로 디자인하는 프레임워크 설계자는 사용자가 'out' 또는 'ref' 매개 변수를 사용하는 작업에 능숙할 것이라고 기대해서는 안된다.

- 참조로 참조 형식을 전달하지 않는다.
 참조를 교환하는 데 사용할 수 있는 메서드와 같이 몇가지 제한된 예외가 있다.

매개 변수 개수가 가변적인 멤버

가변적인 개수의 인수를 사용하는 멤버는 배열 매개 변수를 제공하여 표현된다. 예를들어 String에는 다음과 같은 메서드가 있다.

public class String {
    public static string Format(string format, object[] parameters);
}

사용자는 아래와 같이 String.Format을 호출할 수 있다.

String.Format("File {0} not found in {1}",new object[]{filename,directory});

C# params 키워드를 배열 매개 변수에 추가하면 매개 변수가 params 배열 매개 변수로 변경되고 임시 배열을 만드는 shortcut을 제공한다.

public class String {
    public static string Format(string format, params object[] parameters);
}

사용자는 인수 목록에서 직접 배열 요소를 전달하여 메서드를 호출할 수 있다.

String.Format("File {0} not found in {1}",filename,directory);

* params 키워드는 매개 변수 목록의 마지막 매개 변수에만 추가할 수 있다.

- 최종 사용자가 적은 수의 요소로 배열을 전달할 것으로 예상되는 경우 배열 매개 변수에 params 키워드를 추가하는 것이 좋다. 일반적인 시나리에서 많은 요소가 전달될 것으로 예상되는 경우 사용자는 이러한 요소를 인라인으로 전달할 수 없으므로 params 키워드는 필요하지 않는다.

- 호출자가 거의 항상 배열에 미리 입력하는 경우라면 params 배열을 사용하면 안된다.
 예를들어 바이트 배열 매개 변수를 사용하는 멤버는 개별 바이트를 전달하여 거의 호출되지 않는다. 따라서 .net framework의 바이트 배열 매개 변수는 params 키워드를 사용하지 않는다.

- 배열이 params 배열 매개 변수를 사용하는 멤버에 의해 수정되는 경우라면 params 배열을 사용하지 않는다.
 대부분 컴파일러는 멤버에 대한 인수 호출 시 임시 배열로 변환하기 때문에 배열이 임시 개체가 되어 배열에 대한 수정내용이 손실된다.

- 복잡한 오버로드에서 사용할 수 없는 경우 간단한 오버로드에서 params 키워드를 사용하는 것이 좋다. 모든 오버로드에 포함되지 않는 경우에도 사용자가 하나의 오버로드에 params 배열을 포함하고 있는지 확인한다.

- params 키워드를 사용할 수 있도록 매개 변수의 순서를 지정한다.

- 성능이 중요한 API에서는 적은 수의 인수를 사용하는 호출에 대해 특별한 오버로드 및 코드 경로를 제공하는 것이 좋다.(???)
그러면 적은 수의 인수를 사용하여 API를 호출할 때 배열 개체가 생성되지 않도록 할 수 있다. 단수 형태의 배열 매개 변수를 사용하고 숫자 접미사를 추가하여 매개 변수 이름을 구성한다.
배열을 만들고 일반적인 메서드를 호출하는 것만이 아니라 전체 코드 경로를 특별히 처리하는 경우에 이 작업을 수행해야 한다(???)

- params 배열 인수로 null을 전달할 수 있음을 인식한다. 처리하기 전에 배열이 null이 아닌지 확인한다.

- 줄임표로도 알려져 있는 'varargs' 메서드를 사용하지 않는다.
 C++과 같은 일부 CLR 언어에서는 varargs 메서드라는 매개 변수 목록을 전달하는 대체 규칙을 지원한다. 규칙은 CLS 규격이 아니기 때문에 프레임워크에서는 사용해서는 안된다.

포인터 매개 변수

일반적으로 포인터는 잘 디자인된 코드 프레임워크의 public 영역에 노출되면 안된다. 대부분 경우 포인터를 캡슐화 해야한다. 그러나 상호 운용성을 위해 포인터가 필요한 경우가 있으며 이런 경우 포인터를 사용하기에 적합하다.

- 포인터는 CLS 규격이 아니므로 포인터 인수를 사용하는 모든 멤버의 대안을 제공한다.
- 포인터 인수에 대해서는 비용이 많이 드는 인수 확인을 수행하면 안된다.
- 포인터를 사용하여 멤버를 디자인할 떄는 일반적인 포인터 관련 규칙을 따른다.
 예를 들어 간단한 포인터 산술을 사용하여 동일한 겨로가를 얻을 수 있으므로 시작 인덱스를 전달할 필요가 ㅇ벗다.

728x90
반응형