필수는 아니지만 선택적 매개 변수 이름을 지정 하시겠습니까?


25

다음 방법을 고려하십시오.

public List<Guid> ReturnEmployeeIds(bool includeManagement = false)
{

}

그리고 다음 전화 :

var ids = ReturnEmployeeIds(true);

시스템을 처음 사용하는 개발자의 경우 어떤 일을 true했는지 추측하기가 매우 어렵습니다 . 가장 먼저 할 일은 메소드 이름 위로 마우스를 가져 가거나 정의로 이동하는 것입니다 (두 가지 중 가장 큰 작업은 아닙니다). 그러나 가독성을 위해 다음과 같이 작성하는 것이 합리적입니다.

var ids = ReturnEmployeeIds(includeManagement: true);

컴파일러가 필요하지 않을 때 선택적 매개 변수를 명시 적으로 지정할지 여부를 공식적으로 논의하는 곳이 있습니까?

다음 문서에서는 특정 코딩 규칙에 대해 설명합니다. https://msdn.microsoft.com/en-gb/library/ff926074.aspx

위의 기사와 비슷한 것이 좋습니다.


2
다음은 다소 관련이없는 두 가지 질문입니다. (1) 명확성을 위해 선택적 인수를 작성해야합니까? (2) boolean메소드 인수를 사용해야 하며 어떻게해야합니까?
Kilian Foth

5
이것은 모두 개인 취향 / 스타일 / 의견으로 요약됩니다. 개인적으로, 전달 된 값이 리터럴 인 경우 매개 변수 이름이 좋습니다 (변수는 이미 이름을 통해 충분한 정보를 전달할 수 있습니다). 그러나 그것은 내 개인적인 견해입니다.
MetaFight

1
귀하의 질문에 해당 링크를 예제 소스로 포함 하시겠습니까?
MetaFight

4
그것이 추가되면 StyleCop & ReSharper를 통해 실행했습니다. ReSharper에서 단순히 명명 된 매개 변수라고 할 수 제거하고 명명 된 매개 변수가 말을 계속 할 수있는 추가 될 수있다. 내가 추측하는 이유에 대한 조언은 무료입니다 ... :-/
Robbie Dee

답변:


28

C # 세계에서는 열거 형이 가장 좋은 옵션 중 하나라고 말하고 싶습니다.

그것으로 당신은 당신이하고있는 일을 철회해야하며 모든 사용자는 무슨 일이 일어나고 있는지 볼 것입니다. 또한 향후 확장에도 안전합니다.

public enum WhatToInclude
{
    IncludeAll,
    ExcludeManagement
}

var ids = ReturnEmployeeIds(WhatToInclude.ExcludeManagement);

내 의견으로는 여기 :

열거 형> 선택적 열거 형> 선택적 bool

편집 : 아래의 LeopardSkinPillBoxHat [Flags]와이 특정 사례에서 (적어도 포함 / 제외에 대해 이야기하고 있기 때문에) 적합 할 수 있는 열거 형 에 대한 논의로 인해 ISet<WhatToInclude>매개 변수로 사용 하는 것이 좋습니다.

LINQ 컬렉션에 적합하지만 [Flags]최대 32 개의 그룹 이 있다는 사실에서 비롯된 몇 가지 장점이있는보다 "현대적인"개념입니다 . 사용의 주요 단점은 ISet<WhatToInclude>C # 구문에서 집합이 잘못 지원되는 방식입니다.

var ids = ReturnEmployeeIds(
    new HashSet<WhatToInclude>(new []{ 
        WhatToInclude.Cleaners, 
        WhatToInclude.Managers});

그 중 일부는 다음과 같은 "바로 가기 세트"를 생성하고 설정하기 위해 도우미 기능으로 완화 될 수 있습니다.

var ids = ReturnEmployeeIds(WhatToIncludeHelper.IncludeAll)

나는 동의하는 경향이있다. 나중에 조건이 확장 될 가능성이 모호한 경우 일반적으로 새 코드에서 열거 형을 사용했습니다. 무언가가 3 상태가 될 때 부울을 열거 형으로 바꾸면 실제로 시끄러운 diff를 생성하고 비난 코드를 훨씬 지루하게 만듭니다. 3 년째 옵션으로 1 년에 한 번씩 코드를 다시 수정해야하는 경우
Dan Neely

3
등 I enum방법,하지만 난 혼합의 거대한 팬이 아니에요 IncludeExclude같은에서 enum그것은 무슨 일이 일어나고 있는지 파악하는 것이 더 어렵다있다. 이것이 정말로 확장 가능하기를 원한다면, 그것을 [Flags] enum만들고 IncludeXxx, 모두 만들고 , IncludeAll로 설정된 것을 제공 할 수 Int32.MaxValue있습니다. 그런 다음 2 개의 ReturnEmployeeIds과부하 를 제공 할 수 있습니다. 하나는 모든 직원 을 반환 하고 다른 하나 WhatToInclude는 열거 형 플래그의 조합 일 수 있는 필터 매개 변수를 사용합니다.
LeopardSkinPillBoxHat

@LeopardSkinPillBoxHat 좋아요, 제외 / 포함에 동의합니다. 그래서 이것은 약간의 고안된 예이지만, IncludeAllButManagement라고 부를 수 있습니다. 당신의 다른 점에서, 나는 동의하지 않습니다-나는 [Flags]유물 이라고 생각 하며 레거시 또는 성능상의 이유로 만 사용해야합니다. 나는 a ISet<WhatToInclude>가 훨씬 더 나은 개념 이라고 생각합니다 (불행히도 C #에는 사용하기 좋은 구문 설탕이 부족합니다).
NiklasJ

@NiklasJ- Flags발신자가 통과 WhatToInclude.Managers | WhatToInclude.Cleaners하고 비트 단위로 또는 발신자가 처리하는 방식 (예 : 관리자 또는 클리너)을 정확하게 표현 하기 때문에이 방법이 마음에 듭니다 . 직관적 인 구문 설탕 :-)
LeopardSkinPillBoxHat

@LeopardSkinPillBoxHat 정확하지만, 그 방법의 유일한 단점입니다. 단점은 예를 들어 제한된 수의 선택을 포함하며 다른 linq와 같은 개념과 호환되지 않습니다.
NiklasJ

20

쓰는 것이 합리적입니까?

 var ids=ReturnEmployeeIds(includeManagement: true);

이것이 "좋은 스타일"이라면 논쟁의 여지가 있지만, IMHO 이것은 최소한 나쁜 스타일이 아니며, 코드 라인이 "너무 길지"않은 한 유용하다. 명명 된 매개 변수가 없으면 설명 변수를 도입하는 일반적인 스타일이기도합니다.

 bool includeManagement=true;
 var ids=ReturnEmployeeIds(includeManagement);

명명 된 매개 변수는 버전 4.0 이전의 언어의 일부가 아니기 때문에이 스타일은 명명 된 매개 변수 변형보다 C # 프로그래머에게 더 일반적 일 것입니다. 가독성에 대한 영향은 거의 동일하며 추가 코드 줄만 있으면됩니다.

따라서 내 권장 사항 : 이름이 다른 열거 형 또는 두 개의 함수를 사용하는 것이 "과잉"이라고 생각하거나 다른 이유로 서명을 변경하지 않으려는 경우 이름 지정된 매개 변수를 사용하십시오.


두 번째 예에서 추가 메모리를 사용하고 있음을 알 수 있습니다.
Alvaro

10
@Alvaro 사소한 경우 (변수가 상수 값을 갖는 경우)에는 사실이 아닐 가능성이 큽니다. 그랬더라도 언급 할 가치가 거의 없습니다. 우리 대부분은 요즘 4KB의 RAM에서 실행되고 있지 않습니다.
Chris Hayes

3
이것은 C #이므로 includeManagement로컬로 표시 하고 const추가 메모리를 전혀 사용하지 않아도됩니다.
Jacob Krall

8
얘들 아, 나는 내가 여기에 중요하다고 생각하는 것을 방해 할 수있는 물건을 내 대답에 추가하지 않을 것이다.
Doc Brown

17

다음과 같은 코드가 발생하면

public List<Guid> ReturnEmployeeIds(bool includeManagement = false)
{

}

당신은 의지 안에 무엇이 있는지를 거의 보장 할 수 있습니다 {}:

public List<Guid> ReturnEmployeeIds(bool includeManagement = false)
{
    if (includeManagement)
        return something
    else
        return something else
}

즉, 부울은 두 가지 행동 과정 중에서 선택하는 데 사용됩니다.이 방법에는 두 가지 책임이 있습니다. 이것은 코드 냄새가 거의 보장 됩니다. 우리는 항상 메소드가 한 가지 작업 만 수행하도록 노력해야합니다. 그들은 하나의 책임이 있습니다. 따라서 두 솔루션 모두 잘못된 접근 방식이라고 주장합니다. 선택적 매개 변수를 사용한다는 것은 메소드가 하나 이상의 작업을 수행한다는 표시입니다. 부울 매개 변수도 이것의 표시입니다. 두 가지 모두 알람 벨을 울리도록 설정해야합니다. 따라서해야 할 일은 서로 다른 두 가지 기능 세트를 두 개의 개별 메소드로 리팩토링하는 것입니다. 다음과 같이 메소드 이름을 밝히십시오.

public List<Guid> GetNonManagementEmployeeIds()
{

}

public List<Guid> GetAllEmployeeIds()
{

}

이렇게하면 코드의 가독성이 향상되고 SOLID 원칙을 더 잘 준수 할 수 있습니다.

편집 의견에서 지적했듯이,이 두 가지 방법에는 공유 기능이있을 가능성이 있으며 공유 기능은 개인 기능으로 래핑되어 부울 매개 변수가 필요한 작업의 일부 측면을 제어하는 ​​것이 가장 좋습니다. .

이 경우 컴파일러가 필요하지 않더라도 매개 변수 이름을 제공해야합니까? 나는 그것에 대한 간단한 대답이 없으며 사례별로 판단해야한다고 제안합니다.

  • 이름을 지정하는 주장은 다른 개발자 (6 개월 내에 자신을 포함하여)가 코드의 주요 대상이되어야한다는 것입니다. 컴파일러는 확실히 2 차 독자입니다. 따라서 다른 사람들이 쉽게 읽을 수 있도록 항상 코드를 작성하십시오. 컴파일러가 필요로하는 것을 제공하는 것보다 우리가 매일이 규칙을 사용하는 방법의 예는 코드에 변수 _1, _2 등을 채우지 않고 의미있는 이름을 사용한다는 것입니다 (컴파일러에는 아무런 의미가 없습니다).
  • 반대 주장은 개인 메소드가 구현 세부 사항이라는 것입니다. 아래와 같은 방법을 보는 사람이라면 누구나 코드 내부를 추적하면서 부울 매개 변수의 목적을 이해하기 위해 코드를 추적 할 것으로 예상 할 수 있습니다.
public List<Guid> GetNonManagementEmployeeIds()
{
    return ReturnEmployeeIds(true);
}

소스 파일과 메소드가 작고 이해하기 쉬운가? 그렇다면, 명명 된 매개 변수는 아마도 노이즈에 해당합니다. 그렇지 않으면 매우 도움이 될 수 있습니다. 따라서 상황에 따라 규칙을 적용하십시오.


12
나는 당신이 말하는 것을 들었지만 당신은 내가 묻는 것의 요점을 놓쳤습니다. 선택적 매개 변수를 사용 하는 것이 가장 적합한 시나리오를 가정하면 (이 시나리오가 존재하는 경우) 불필요하더라도 매개 변수의 이름을 지정해도 괜찮습니까?
JᴀʏMᴇᴇ

4
모두 사실이지만 문제는 그러한 방법 의 호출 에 관한 것이 었습니다 . 또한 플래그 매개 변수는 메서드 내에서 분기를 전혀 보장하지 않습니다. 단순히 다른 레이어로 전달 될 수 있습니다.
Robbie Dee

이것은 잘못된 것이 아니라 지나치게 단순화 한 것입니다. 실제 코드 public List<Guid> ReturnEmployeeIds(bool includeManagement) { calculateSomethingHereForBothBranches; if (includeManagement) return something else return something else }에서는를 찾을 수 있으므로 간단히 두 가지 방법으로 나누면 두 가지 방법으로 매개 변수로 첫 번째 계산 결과가 필요할 것입니다.
Doc Brown

4
우리 모두가 말하는 것은 클래스 의 공개 얼굴이 아마도 두 가지 방법 (각각 하나의 책임이 있음)을 노출해야한다고 생각하지만 내부적으로 이러한 각 메소드는 분기 bool 매개 변수 를 사용하여 단일 개인 메소드로 요청을 합리적으로 전달할 수 있습니다 .
MetaFight

1
두 기능이 다른 동작에 대해 세 가지 경우를 상상할 수 있습니다. 1. 다른 전처리가 있습니다. 공용 함수가 인수를 전용 함수로 사전 처리하도록합니다. 2. 다른 사후 처리가 있습니다. 공용 함수가 개인 함수의 결과를 후 처리하도록하십시오. 3. 중간 동작이 다릅니다. 언어가 지원한다고 가정하면 개인 함수에 람다로 전달 될 수 있습니다. 종종 이것은 이전에는 실제로 발생하지 않았던 재사용 가능한 새로운 추상화로 이어집니다.
jpmc26

1

시스템을 처음 접하는 개발자에게는 실제로 무엇을했는지 추측하기가 매우 어렵습니다. 가장 먼저 할 일은 메소드 이름 위로 마우스를 가져 가거나 정의로 이동하는 것입니다 (두 가지 중 가장 큰 작업은 아닙니다)

예, 맞습니다 자체 문서화 코드는 아름다운 것입니다. 다른 답변에서 지적했듯이 ReturnEmployeeIds열거 형, 다른 메소드 이름 등을 사용하여 호출의 모호성을 제거하는 방법이 있습니다. 그러나 때로는 사건을 피할 수는 없지만 떠나고 싶지는 않습니다. (비주얼 베이직의 장황함을 좋아하지 않는 이상)

예를 들어, 한 통화를 명확하게하는 데 도움이 될 수 있지만 반드시 다른 통화는 아닙니다.

명명 된 인수가 여기에 도움이 될 수 있습니다.

var ids = ReturnEmployeeIds(includeManagement: true);

추가 명확성을 추가하지 마십시오 (이것은 열거 형을 파싱한다고 추측 할 것입니다).

Enum.Parse(typeof(StringComparison), "Ordinal", ignoreCase: true);

실제로 명료성을 떨어 뜨릴 수 있습니다 (사람이 목록의 용량을 이해하지 못하는 경우).

var employeeIds = new List<int>(capacity: 24);

또는 좋은 변수 이름을 사용하기 때문에 중요하지 않은 곳 :

bool includeManagement = true;
var ids = ReturnEmployeeIds(includeManagement);

컴파일러가 필요하지 않을 때 선택적 매개 변수를 명시 적으로 지정할지 여부를 공식적으로 논의하는 곳이 있습니까?

AFAIK가 아닙니다. 명명 된 매개 변수를 명시 적으로 사용해야하는 유일한 시간은 컴파일러에서 요구하기 때문입니다 (일반적으로 명령문 모호성을 제거해야 함). 그 외에는 언제든지 원할 때 사용할 수 있습니다. MS 의이 기사에는 언제 사용할 것인지에 대한 제안이 있지만 특히 https://msdn.microsoft.com/en-us/library/dd264739.aspx는 아닙니다 .

개인적으로, 나는 사용자 정의 속성을 만들거나 매개 변수가 변경되거나 순서를 바꿀 수있는 새로운 방법을 제거 할 때 가장 자주 사용한다는 것을 알았습니다 (b / c 명명 된 속성은 어떤 순서로나 나열 할 수 있음). 또한 정적 값을 인라인으로 제공 할 때만 사용합니다. 그렇지 않으면 변수를 전달하면 좋은 변수 이름을 사용하려고합니다.

TL; DR

궁극적으로 그것은 개인 취향에 달려 있습니다. 물론 명명 된 매개 변수를 사용해야 할 때 몇 가지 사용 사례가 있지만 그 후에 판단을 내려야합니다. IMO-코드를 문서화하거나 모호성을 줄이거 나 메소드 서명을 보호 할 수 있다고 생각되는 곳이라면 어디에서나 사용하십시오.


0

메소드의 (정규화 된) 이름에서 매개 변수가 명확하고 존재하는 것이 메소드의 고유 한 특성 인 경우, 명명 된 매개 변수 구문을 사용 하지 않아야 합니다. 예를 들어 직원의 ID ReturnEmployeeName(57)라는 57것이 분명 하기 때문에 명명 된 매개 변수 구문으로 주석을 추가하는 것은 중복됩니다.

으로 ReturnEmployeeIds(true)당신이 말했듯이 함수의 선언 / 문서를보고하지 않는 한, 무슨 그림을 불가능 true수단 - 당신이 그렇게 해야 명명 된 매개 변수 구문을 사용합니다.

이제이 세 번째 경우를 고려하십시오.

void PrintEmployeeNames(bool includeManagement) {
    foreach (id; ReturnEmployeeIds(includeManagement)) {
        Console.WriteLine(ReturnEmployeeName(id));
    }
}

명명 된 매개 변수 구문은 여기에 사용되지 않지만 변수를에 전달 ReturnEmployeeIds하고 해당 변수에 이름이 있으므로 해당 이름은 전달하는 매개 변수와 동일한 의미를 갖습니다 (이 경우는 종종-그러나 항상 그렇지는 않습니다!)-코드에서 의미를 이해하기 위해 명명 된 매개 변수 구문이 필요하지 않습니다.

따라서 규칙은 간단 합니다. 매개 변수의 의미를 메서드 호출 만으로 쉽게 이해할 수 있으면 명명 된 매개 변수를 사용하지 마십시오. 당신이 할 수 없다면-그것은 코드의 가독성에 결함이 있으며, 아마도 그것들을 고치기를 원할 것입니다 (물론 어떤 가격으로도 아니지만 일반적으로 코드를 읽을 수 있기를 원합니다). 수정은 매개 변수로 이름을 지정할 필요가 없습니다. 최종 결과로 매개 변수의 기능을 쉽게 이해할 수있는 한, 먼저 변수에 값을 넣거나 다른 답변에서 제안 된 방법을 사용할 수 있습니다.


7
나는 ReturnEmployeeName(57)그것이 57ID 라는 것을 즉시 명백하게한다는 것에 동의하지 않습니다 . GetEmployeeById(57)반면에 ...
휴고 Zink

@HugoZink 처음에는 예제와 같은 것을 사용하고 싶었지만 ReturnEmployeeName메서드 이름에 매개 변수를 명시 적으로 언급하지 않아도 사람들이 무엇인지 파악하는 것이 합리적 인 경우를 보여주기 위해 의도적으로 변경했습니다 . 어쨌든 매개 변수의 의미를 나타내는 ReturnEmployeeName이름 ReturnEmployeeIds으로 합리적으로 이름 을 바꿀 수는 없습니다 .
Idan Arye

1
어쨌든 실제 프로그램에서 ReturnEmployeeName (57)을 작성할 가능성은 거의 없습니다. ReturnEmployeeName (employeeId)을 작성할 가능성이 훨씬 높습니다. 직원 ID를 하드 코딩하는 이유는 무엇입니까? 프로그래머의 ID가 아니며 사기가 발생하지 않는 한이 직원의 월급에 약간을 추가하십시오. :-)
Jay

0

예, 스타일이 좋다고 생각합니다.

부울 및 정수 상수에 가장 적합합니다.

변수를 전달하는 경우 변수 이름에 의미가 명확해야합니다. 그렇지 않은 경우 변수에 더 나은 이름을 지정해야합니다.

문자열을 전달하면 의미가 분명합니다. GetFooData ( "Oregon")에 대한 호출을 보는 것처럼 독자는 매개 변수가 상태 이름 인 것으로 추측 할 수 있습니다.

물론 모든 줄이 분명하지는 않습니다. GetFooData ( "M")가 표시되면 함수를 모르면 "M"의 의미를 모릅니다. M = "관리 수준의 직원"과 같은 코드 인 경우 리터럴이 아닌 열거 형이 있어야하며 열거 형 이름이 명확해야합니다.

그리고 문자열이 오도 될 수 있다고 생각합니다. 어쩌면 위의 예에서 "오레곤"은 상태가 아니라 제품이나 클라이언트 또는 무엇이든 가리 킵니다.

그러나 GetFooData (true) 또는 GetFooData (42) ... 그것은 무엇이든 의미 할 수 있습니다. 명명 된 매개 변수는 자체 문서화를 만드는 훌륭한 방법입니다. 나는 여러 차례에 그 목적을 위해 정확하게 사용했습니다.


0

왜 이런 유형의 구문을 사용해야하는지에 대한 명확한 이유 는 없습니다 .

일반적으로 먼 거리에서 임의적으로 보일 수있는 부울 인수가 없도록하십시오. includeManagement결과에 큰 영향을 미칠 것입니다. 그러나이 주장은 "약간 무게가 가벼워"보인다.

열거 형의 사용은 "더 많은 무게를 지니고있다"는 주장처럼 보일뿐만 아니라이 방법에 대한 확장 성을 제공 할 것입니다. 그러나 방법 ReturnEmployeeIdsWhatToInclude-enum 과 함께 확장되어야하기 때문에 이것이 모든 경우에 가장 좋은 해결책 은 아닙니다 ( NiklasJ 의 답변 참조 ). 나중에 두통이 생길 수 있습니다.

이것을 고려하십시오 : 당신이 확장 할 경우 WhatToInclude-enum을하지만 ReturnEmployeeIds-method합니다. 그런 다음 ArgumentOutOfRangeException(가장 좋은 경우) 를 던지 거나 완전히 원하지 않는 것을 반환 null하거나 비어 List<Guid>있습니다. 어떤 경우에는 특히 ReturnEmployeeIds소스 코드를 쉽게 사용할 수없는 클래스 라이브러리에있는 경우 프로그래머를 혼란스럽게 할 수 있습니다.

연수생이 모두의 "부분 집합"인 것을 보아도 가능할 것이라고 생각할 것 WhatToInclude.Trainees입니다 WhatToInclude.All.

이것은 물론 구현 방법에 달려 ReturnEmployeeIds있습니다.


부울 인수가 전달 될 수있는 경우 대신 두 가지 방법 (또는 필요한 경우 더 많이)으로 나누려고합니다. 하나 추출 수 ReturnAllEmployeeIds, ReturnManagementIdsReturnRegularEmployeeIds. 여기에는 모든 기반이 포함되며이를 구현하는 사람에게는 절대적으로 설명이 필요합니다. 또한 위에서 언급 한 "확장"문제가 없습니다.

부울 인수가있는 결과두 가지 뿐입니다 . 두 가지 방법을 구현하면 추가 노력이 거의 들지 않습니다.

코드가 적을수록 드물다.


이 말한다면, 거기에 있는 명시 적으로 인수를 선언 가독성을 향상 경우가. 예를 들어보십시오. GetLatestNews(max: 10). GetLatestNews(10)이다 여전히 꽤 자기 설명의 명시 적 선언 max의 뜻 도움이 정리 모든 혼란을.

당신이 만약 절대적으로 있어야 부울 인수를 가지고있는 사용하는 것은 단지 읽기에 의해 추론 할 수없는 truefalse. 그런 다음 나는 말할 것입니다 :

var ids = ReturnEmployeeIds(includeManagement: true);

..는 다음보다 절대적으로 더 좋고 읽기 쉽습니다.

var ids = ReturnEmployeeIds(true);

두 번째 예에서는 true의미가 무엇이든 의미 할 수 있습니다 . 그러나 나는이 논쟁을 피하려고 노력할 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.