params 키워드를 사용하는 이유는 무엇입니까?


336

나는 이것이 기본적인 질문이라는 것을 알고 있지만 답을 찾을 수 없습니다.

왜 사용합니까? 함수 또는 함수를 사용하는 메소드를 작성하는 경우 코드를 제거해도 코드가없는 것처럼 100 % 완벽하게 작동합니다. 예 :

params로 :

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

매개 변수없이 :

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}

62
메소드 자체의 코드는 여전히 완벽하게 작동합니다 ... 호출 코드는 제대로 작동 하지 않을 수 있습니다 ...
Jon Skeet

7
params 키워드는 메소드에 전달되거나 전달되지 않을 수있는 선택적 매개 변수를 의미합니다. 매개 변수 키워드가없는 배열은 반드시 배열 인수를 메소드에 전달해야 함을 의미합니다.
Ailayna Entarria

파이썬 언어는 여기에* 언급 된 것과 같이 별표 ( ) 접두사가 붙은 매개 변수를 사용 하여 동일한 개념을 구현합니다 .
RBT

답변:


485

다음과params 같이 메소드를 호출 할 수 있습니다.

addTwoEach(1, 2, 3, 4, 5);

없이는 params할 수 없습니다.

또한 두 경우 모두 배열을 매개 변수로 사용하여 메서드를 호출 할 수 있습니다 .

addTwoEach(new int[] { 1, 2, 3, 4, 5 });

params, 메서드를 호출 할 때 바로 가기를 사용할 수 있습니다.

관련이없는 방법을 크게 단축 할 수 있습니다.

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}

17
@Ken : 당신은 수입해야 할 수도 있습니다 System.Linq네임 스페이스 :
Ranhiru 유 Cooray

49
또는 args.Sum (i => i + 2)을 반환합니다.
bornfromanegg

2
그러나 대리인과의 합은 컴파일 된 코드의 복잡성을 증가시켜 잠재적으로 성능이 떨어질 수 있습니다. 클로즈가 발생하지 않으므로이 특정 상황에서는 실제로 관련이 없지만 컴파일러가 실제로 최선의 선택을하기 위해 무엇을하는지 아는 것은 가치가 있습니다.
Allen Clark Copeland Jr

2
당신은 또한 사용할 수 있습니다 return args.Select(x => x + 2).Sum();
bbvg

1
당신이 추가 할 때 params당신은 발신자 또는 방법 해상도를 파괴하지 않고 추가 메소드 인수를 추가하는 자신을.
Mr. Young

93

를 사용 params하면 인수없이 함수를 호출 할 수 있습니다. 없이 params:

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

와 비교 params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

일반적으로 인수 수가 0에서 무한대까지 다양 할 수있는 경우 매개 변수를 사용하고 인수 수가 1에서 무한대까지 다양 할 경우 배열을 사용할 수 있습니다.


13
실제로 배열은 비어있을 수 있습니다. new int[0]. 도움이 되었기를 바랍니다! :)
vidstige

22

통화에 원하는만큼 기본 유형 매개 변수를 추가 할 수 있습니다.

addTwoEach(10, 2, 4, 6)

반면 두 번째 형식에서는 배열을 매개 변수로 사용해야합니다

addTwoEach(new int[] {10,2,4,6})

17

한 가지 위험 params키워드는 경우입니다 메서드를 호출하면, 코딩 된

  1. 누군가가 실수로 / 의도적으로 하나 / 더 제거 필요 메소드 서명에서 매개 변수를
  2. 서명 변경 직전의 파라미터 직전의 1 개 이상의 필수 파라미터가 params파라미터와 형식 호환이 가능한 params,

이러한 호출은 선택적 매개 변수로 취급되는 필수 매개 변수에 대해 이전에 의도 한 하나 이상의 표현식으로 계속 컴파일됩니다 params. 방금 최악의 경우가 발생했습니다. params매개 변수는 유형이었습니다.object[] 입니다.

개발자가 컴파일러가 손목을 때리는 데 필요한 모든 매개 변수가있는 메소드에서 매개 변수가 제거되는 훨씬 일반적인 시나리오 (예상되는 매개 변수 수가 변경되기 때문에)에 익숙하기 때문에 주목할 만합니다 .

저에게는 지름길 가치가 없습니다. (Type)[]without params는 재정의없이 0에서 무한대까지의 매개 변수로 작동합니다. 최악의 경우 , new (Type) [] {}적용되지 않는 통화에 통화 를 추가 해야합니다.

Btw, imho, 가장 안전하고 읽기 쉬운 방법은 다음과 같습니다.

  1. 명명 된 매개 변수를 통해 전달하십시오 ( VB; P에서 수십 년이 지난 후 C # ~ 20 년 에도 가능합니다 ).

    1.1. 매개 변수 순서, 호환 유형 및 / 또는 호출이 코딩 된 후 카운트 변경 후에 의도하지 않은 값이 매개 변수로 전달 되는 것을 방지 할 수 있는 유일한 방법입니다 .

    1.2. 그것은 감소 새로운 의미를 반영하는 것으로 새로운 식별자 이름 바로 옆 값에 전달되기 때문에, 파라미터 변화 후의 의미 그 가능성

    1.3. 쉼표를 계산하지 않고 Call to Signature에서 앞뒤로 건너 뛰어 어떤 매개 변수에 어떤식이 전달되는지 확인합니다.

    1.3.1. 그런데, 이런 이유로 혼자가해야 많은 (그냥하는 DRY 원칙의 잦은 오류가 발생하기 쉬운 위반을 방지 측면에서 읽을 코드도 언급하지 않기 수정 을)하지만,이 이유가 될 수 있습니다 기하 급수적으로 하나가있는 경우 더 중요 / 쉼표를 포함하는 더 많은 표현식 (예 : Multi-Dimensional Array Refs 또는 Multi-Parameter Function Calls) 이 경우 편집기에서 선택 항목의 모든 발생 항목 찾기 기능을 사용하여 (메서드 호출 매개 변수 마다 추가 단계를 계속 추가 할 수도 있음 ) 쉼표 계산을 자동화 할 수 없습니다.

    1.4. 선택적 매개 변수를 사용해야하는 경우 (선택적 params) 특정 선택적 매개 변수가 전달 된 통화를 검색 할 수 있습니다 (따라서 기본값이 아닐 수도 있고 최소한 기본값이 아닐 수도 있음).

(참고 : 이유 1.2. 및 1.3은 호출을 읽고 / 또는 변경해야 할 때 언급하지 않고 초기 호출을 코딩 할 때도 오류 가능성을 줄이고 줄일 수 있습니다.)

  1. 가독성을 높이기 위해 1 개의 PARAMETER-PER-LINE을 사용하십시오.

    2.1. 덜 어수선하고

    2.2. 그것은 좌우로 스크롤 할 필요가 없습니다 (그리고 대부분의 필사자는 여러 줄의 왼쪽 부분을 읽을 수 없으므로 오른쪽으로 스크롤하고 오른쪽 부분을 읽을 수 있기 때문에 PER-LINE을 수행해야 함).

    2.3. 전달 된 모든 매개 변수가 본질적으로 지정 문 (값 또는 참조를 로컬 변수에 지정)이기 때문에 지정 문에 대해 이미 발전시킨 "모범 사례"와 일치합니다. 코딩 스타일에서 최신 "Best Practice" 를 따르는 사람들이 한 줄에 여러 개의 Assignment Statements를 코딩하는 것을 꿈꾸지 않는 것처럼, "Best Practice" 내 "천재"를 따라 잡지 않아야합니다 . )는 매개 변수를 전달할 때 수행합니다.

참고 사항 :

  1. 이름이 매개 변수를 반영하는 변수를 전달하면 다음과 같은 경우 도움이되지 않습니다.

    1.1. 리터럴 상수를 전달하는 경우 (예 : " '모범 사례'"조차도 명명 된 상수를 사용할 필요가없고 목적 이름을 메소드 이름에서 쉽게 추론 할 수없는 단순한 0/1, false / true 또는 null 임) ),

    1.2. 이 메소드는 호출자보다 훨씬 저수준 / 일반적이므로 변수의 이름을 매개 변수와 동일 / 유사하게 지정하지 않을 수 있습니다 (또는 그 반대).

    1.3. 유형 여전히 호환 가능하기 때문에 이전 통화가 여전히 컴파일 될 수있는 Signature의 매개 변수를 재정렬 / 교체 하고 있습니다.

  2. VS와 같은 자동 줄 바꿈 기능을 사용하면 위에서 언급 한 8 가지 이유 중 하나 (# 2.2) 만 제거됩니다. VS 2015 이전에는 자동 들여 쓰기 (!?! 실제로 MS?!?)하지 않았으므로 이유 # 2.1의 심각도가 증가합니다.

VS에는 명명 된 매개 변수 (한 줄에 하나씩; P)와 메서드 호출 스 니펫을 생성하는 옵션과 명명 된 매개 변수 ( VB의 Option Explicit와 개념 상 유사 함)와 비슷한 컴파일러 옵션이 있어야합니다. 똑같이 터무니 없지만 이제는 ''최고의 관행 ''에 필요합니다 .) 사실, "다시 Day ";), 1991 년에 커리어가 시작된 지 몇 달이 지났는데, 심지어 Named Parameters로 언어를 사용하기 (혹은 본 적이 있기도 전에) 나는 안티-셰이프를 가지고있었습니다. / 맹목적으로 "로스트의 끝을 자르십시오"라는 의미를 가진 사람을 보지 않고 그것을 (인라인 주석을 사용하여) 시뮬레이션하기에 충분하지 않습니다. 명명 된 매개 변수를 사용할 필요가 없습니다. 소스 코드 키 스트로크)는 대부분의 구문이 시작되었을 때 펀치 카드 시대의 유물입니다. 가독성이 많은 현대 하드웨어 및 IDE 및 훨씬 더 복잡한 소프트웨어의 경우에는 변명의 여지가 없습니다. 훨씬더 중요. "코드는 작성된 것보다 훨씬 자주 읽습니다". 자동 업데이트되지 않은 코드를 복제하지 않는 한 누군가 (나 자신도) 나중에 읽으려고 할 때 저장된 모든 키 입력 비용이 기하 급수적으로 더 높아질 수 있습니다.


2
이해가 안 돼요 왜 적어도 하나만 존재하도록 강요 할 수 없습니까? 매개 변수가 없어도 통과 null하거나 new object[0]논쟁으로 막을 수있는 것은 없습니다 .
Casey

선택적 매개 변수보다 먼저 필수 매개 변수를 사용하는 것은 너무 위험 할 수 있습니다 (통화가 코딩 된 후 필요한 매개 변수 중 하나 이상이 제거 된 경우). 그렇기 때문에 선택적 매개 변수에 대한 문서에서 샘플 코드의 선택적 매개 변수 앞에 필수 매개 변수를 본 적이없는 것 같습니다. Btw, imho, 가장 안전하고 읽기 쉬운 방법은 명명 된 매개 변수를 통해 전달하는 것입니다 (이제 VB에서 ~ 20 년 후에도 C # 에서도 수행 할 수 있음). VS에는 명명 된 매개 변수를 사용하여 메서드 호출 스 니펫을 생성하는 옵션이 있어야합니다 (한 줄에 1 개의 매개 변수 수행).
Tom

무슨 말인지 잘 모르겠습니다. 필수 매개 변수 및 선택적 매개 변수를 가질 수있는 유일한 방법은 모든 필수 매개 변수를 먼저 지정하는 것입니다.
Casey

1
전의. 로 선언 myMethod합니다 void myMethod(int requiredInt, params int[] optionalInts). 본인 / 다른 사람이 하나 이상의 통화를 코딩합니다 (예 : myMethod(1), myMethod(1, 21)) myMethod(1, 21, 22). 로 변경 myMethod되었습니다 void myMethod(params int[] optionalInts). 첫 번째 매개 변수 ( "1")가 optionalInts매개 변수 의 첫 번째 요소로 전달되지 않았더라도 이러한 호출은 모두 오류없이 컴파일됩니다 .
Tom

오. 글쎄, 그 특정한 경우에는 잘못 권고 될 수 있습니다. 문자열과 0 대 다수의 정수 등이 필요한 경우 피해야 할 이유가 없다고 생각합니다.
Casey

10

과부하 방법을 만들 필요가 없으며 아래 표시된 것처럼 매개 변수가있는 단일 방법 하나만 사용하십시오.

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);

귀하의 의견에 감사하지만 이러한 유형의 과부하는 params컬렉션 수를 포함하기 위해 컬렉션 유형을 전달하거나 포함하지 않은 이후로 솔루션이 될 것이라고 생각하지 않습니다 .
MasterMastic

당신은 어느 정도는 맞지만 그것을 시원하게 만드는 것은 입력 매개 변수가없는 과부하입니다. int sum1 = addTwoEach ();
electricbah

5

params 또한 단일 인수로 메소드를 호출 할 수 있습니다.

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

Foo(1);대신 Foo(new int[] { 1 });. 전체 배열이 아닌 단일 값을 전달해야하는 시나리오에서 속기에 유용 할 수 있습니다. 여전히 메소드에서 동일한 방식으로 처리되지만이 방법을 호출하기 위해 약간의 사탕을 제공합니다.


5

params 키워드 자체를 추가하면 사용할 수없는 메소드를 호출하는 동안 여러 개의 매개 변수를 전달할 수 있음이 표시됩니다. 보다 구체적으로 :

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

위의 메소드를 호출하면 다음 방법 중 하나로 호출 할 수 있습니다.

  1. addTwoEach()
  2. addTwoEach(1)
  3. addTwoEach(new int[]{ 1, 2, 3, 4 })

그러나 params 키워드를 제거 할 때 위의 세 번째 방법 만 잘 작동합니다. 첫 번째와 두 번째 경우에는 오류가 발생합니다.


0

한 가지 더 중요한 점을 강조해야합니다. params성능이 우수하기 때문에 사용 하는 것이 좋습니다. params인수가 있는 메소드를 호출하고 아무것도 전달하지 않은 경우 :

public void ExampleMethod(params string[] args)
{
// do some stuff
}

요구:

ExampleMethod();

그런 다음 .Net Framework의 새 버전이 .Net Framework 4.6에서 수행합니다.

ExampleMethod(Array.Empty<string>());

Array.Empty개체는 나중에 프레임 워크에서 재사용 할 수 있으므로 중복 할당을 수행 할 필요가 없습니다. 이러한 할당은 다음과 같이이 메소드를 호출 할 때 발생합니다.

 ExampleMethod(new string[] {});

0

바보처럼 들릴지 모르지만 Params는 다차원 배열을 허용하지 않습니다. 반면 다차원 배열을 함수에 전달할 수 있습니다.


0

다른 예시

public IEnumerable<string> Tokenize(params string[] words)
{
  ...
}

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