C # 4.0 선택적 out / ref 인수


212

C # 4.0은 선택적 out또는 ref인수를 허용합니까 ?


2
C ++은 효과적으로 "out"매개 변수를 가지고있다. 주소 인수는 null로 초기화 될 수 있으며 포인터가 널이 아닌 경우에만 이러한 리턴 구조를 채우는 라이브러리 코드를 작성하는 것이 일반적이다. 그것은 C API에서 "선택적 인수"에 null을 사용하는 관용구입니다.
Andy Dent

53
@Ed와 모두 : 왜 이것이 말이되지 않습니까? 함수가 "out"을 통해 값을 "반환"하면 강제로 받아들이고 싶지 않습니다. 이제 기술적 인 이유로 컴파일러가 여전히 무언가를 전달해야한다는 것을 알고 있지만 내 뒤에서 나를 위해 더미 로컬을 만들 수없는 이유는 없습니다.
Roman Starkov

5
사물이 어떻게 구현되는지 또는 선택적 매개 변수가 무엇인지에 대한 관점에서 말이 안될 수도 있습니다. 그러나 롬 킨스가 말했듯이, "선택적 인수"를 갖는 것이 정말 좋을 것입니다. CLR이 아닌 영어로 해석하면 합리적이고 IMO에서는 바람직합니다.
Adam Tolley

9
C #은 그렇지 않지만 VB.NET은 그렇지 않습니다.
Jason

5
그러나 이것은 선택의 여지가 있지만, 선택적인 논쟁에 대한 나의지지를 언급 ​​할 수는 없다. 나는 null기본 설정 ( PHP에서 온 것)을 통해 참조를 통해 선택적 인수에 상당히 익숙해졌습니다. 어쨌든 null인수를 채우는 테스트 ( 친숙한 사람들은 생각합니다preg_match() ) 어쨌든 기술적 인 관점에서 현재 이해 할 수 있습니다. 불가능하다. PHP와 C #은 비교할 수 없지만 여전히 " 좋은 "도구가 될 것이다.
Dan Lugg

답변:


93

이미 언급했듯이 이것은 단순히 허용되지 않으며 매우 의미가 있다고 생각합니다. 그러나 자세한 내용을 추가하려면 C # 4.0 Specification 섹션 21.1 의 인용문을 참조하십시오 .

생성자, 메서드, 인덱서 및 대리자 형식의 형식 매개 변수는 선택적으로 선언 될 수 있습니다.

고정 매개 변수 :
    속성 opt 매개 변수 수정 자 opt 유형 식별자 default-argument opt
default-argument :
    = expression

  • 고정 매개 변수 A를 기본 인수는 입니다 선택적 매개 변수 반면, 고정 매개 변수 없이 기본 인수는 A는 필수 매개 변수 .
  • formal-parameter-list 의 선택적 매개 변수 뒤에 필수 매개 변수가 표시 될 수 없습니다 .
  • ref또는 out매개 변수는 사용할 수 없습니다 기본 인수를 .

또는 ref / out 매개 변수를 사용하여 과부하를 작성할 수 있습니다. 네, 두 개의 함수 정의가있을 것입니다. 그러나 다음에 달성 할 것입니다
Chad

201

아니.

해결 방법은 out / ref 매개 변수 가없고 현재 메서드를 호출하는 다른 메서드로 오버로드하는 것 입니다.

public bool SomeMethod(out string input)
{
    ...
}

// new overload
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

업데이트 : C # 7.0 인 경우 다음을 단순화 할 수 있습니다.

// new overload
public bool SomeMethod()
{
    return SomeMethod(out _);    // declare out as an inline discard variable
}

(이 점을 지적 해준 @Oskar / @Reiner에게 감사합니다.)


6
임시 / 더미를 선언하는 것보다 더 우아한 솔루션에 대한 아이디어가 있습니까?
루이스리스

20
그게 뭐가 우아하지 않습니까? 나에게 완벽하게 보인다.
Neutrino

27
어쩌면 괜찮지 만 우아한 것은 다른 리그에 있습니다. 더 나은 해결책이 없다고해서 이것이 법령에 의해 최첨단임을 의미하는 것은 아닙니다.
o0 '.

7
@ o0 '을 누르고 있습니다. C # 7.0에서는 다음을 수행 할 수 있습니다 return SomeMethod(out string temp).. 자세한 내용은 여기를 참조하십시오 : blogs.msdn.microsoft.com/dotnet/2016/08/24/…
Oskar

7
C # 7.0에서는 다음과 같은 임시 쓰기 전용 변수를 사용할 수 있습니다.return SomeMethod(out _);
Reiner

64

아니요, 그러나 다른 좋은 대안은 다음과 같이 메소드가 선택적 매개 변수에 일반 템플리트 클래스를 사용하도록하는 것입니다.

public class OptionalOut<Type>
{
    public Type Result { get; set; }
}

그런 다음 다음과 같이 사용할 수 있습니다.

public string foo(string value, OptionalOut<int> outResult = null)
{
    // .. do something

    if (outResult != null) {
        outResult.Result = 100;
    }

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    OptionalOut<int> optional = new OptionalOut<int> ();

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);

    // example: call it with named optional parameter
    foo (str, outResult: optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);
}

19
매우 합리적인 해결책이지만, 알아야 할 한 가지는 컴파일러가 메소드를 종료하기 전에 out 매개 변수를 지정해야한다는 요구 사항을 강제하지 않는다는 것입니다.
Ken Smith

2
마음에 들지만 새 클래스를 만들고 싶지 않으면 단일 요소 배열을 전달하여 시뮬레이션 할 수 있습니다.
zumalifeguard

30

실제로 C #에서 허용하는 방법이 있습니다. 이것은 C ++로 돌아가고 C #의 멋진 Object-Oriented 구조를 위반합니다.

이 방법을주의해서 사용하십시오!

선택적 매개 변수를 사용하여 함수를 선언하고 작성하는 방법은 다음과 같습니다.

unsafe public void OptionalOutParameter(int* pOutParam = null)
{
    int lInteger = 5;
    // If the parameter is NULL, the caller doesn't care about this value.
    if (pOutParam != null) 
    { 
        // If it isn't null, the caller has provided the address of an integer.
        *pOutParam = lInteger; // Dereference the pointer and assign the return value.
    }
}

그런 다음 다음과 같이 함수를 호출하십시오.

unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.

이를 컴파일하려면 프로젝트 옵션에서 안전하지 않은 코드를 활성화해야합니다. 이것은 일반적으로 사용해서는 안되는 매우 해킹 된 솔루션이지만 이상한 이상한 신비한 관리 영감을 얻은 결정에 정말로 C #에서 선택적 매개 변수가 필요하다면 그렇게 할 수 있습니다.


6

ICYMI는 : 열거 된 C # 7.0의 새로운 기능에 포함 된 여기에 , "폐기"가 지금의 형태 _의 매개 변수 아웃으로 허용, 당신은 당신이 걱정하지 않는 매개 변수를 무시하도록하려면 :

p.GetCoordinates(out var x, out _); // I only care about x

PS "out var x"부분과 혼동되는 경우 링크에서 "Out Variables"에 관한 새로운 기능을 읽으십시오.


_ 또는 * "p.GetCoordinates (out int x, out *); // x에만 관심이 있습니다"
Onur Topal

이전 버전의 문서를보고있는 것 같습니다.
Onur Topal

2

아니요, 대신 대리인 (예 :)을 사용할 수 있습니다 Action.

선택적 매개 변수를 원한다고 생각하는 상황에 직면했을 때 Robin R의 대답에서 부분적으로 영감을 얻은 대신 Action대리자 를 사용했습니다 . Action<int>차이점과 유사성을 보여주기 위해 그의 예제 코드를 빌려 사용하도록 수정했습니다 .

public string foo(string value, Action<int> outResult = null)
{
    // .. do something

    outResult?.Invoke(100);

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    int optional = 0;

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);

    // example: call it with named optional parameter
    foo (str, outResult: x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);
}

이는 선택적 변수가 소스에 일반 int로 표시되는 이점이 있습니다 (컴파일러는 사용자 정의 클래스로 명시 적으로 래핑하지 않고 클로저 클래스로 래핑합니다).

컴파일러는 Action함수 호출이 종료되기 전에 의지가 호출 될 것이라고 가정 할 수 없으므로 변수를 명시 적으로 초기화해야합니다 .

모든 유스 케이스에 적합하지는 않지만 실제 유스 케이스 (단위 테스트를위한 데이터를 제공하는 함수 및 새로운 단위 테스트가 리턴 값에 존재하지 않는 일부 내부 상태에 액세스 해야하는 기능)에서는 잘 작동했습니다.


0

out 매개 변수없이 오버로드 된 메서드를 사용하여 C # 6.0 이하의 out 매개 변수가있는 메서드를 호출하십시오. C # 4.0에 선택적 출력 매개 변수가 있는지 여부를 구체적으로 물었을 때 .NET Core 용 C # 7.0이이 스레드에 대한 정답 인 이유를 잘 모르겠습니다. 내 대답은 아니오 야!


-2

이건 어때?

public bool OptionalOutParamMethod([Optional] ref string pOutParam)
{
    return true;
}

여전히 C #에서 매개 변수로 값을 전달해야하지만 선택적 ref 매개 변수입니다.


8
“여전히 C #에서 매개 변수에 값을 전달해야합니다.”... 이것은 선택 사항이 아닙니다.
Arturo Torres Sánchez

C #은 [Optional]주석을 무시합니다 . 도움이되지 않습니다.
ToolmakerSteve

-4
void foo(ref int? n)
{
    return null;
}

1
모든 사람들이 개념을 쉽게 이해할 수 있도록 코드에 대한 설명을 추가하십시오
techspider

1
이 코드는 질문에 대답 할 수 있지만, 질문에 대한 이유 및 / 또는 방법 에 대한 추가 컨텍스트를 제공 하면 장기적인 가치가 크게 향상됩니다. 제발 편집 약간의 설명을 추가 할 답변을.
Toby Speight

2
메소드에 void 리턴 유형이 있으므로 구문 오류가 발생합니다. 또한 질문에 대답하지 않습니다.
Nathan Montez
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.