무효 또는 부울 return+out 매개 변수를 사용하여 더 좋습니다.

StackOverflow https://stackoverflow.com/questions/1800003

  •  05-07-2019
  •  | 
  •  

문제

정수 값을 반환 해야하는 함수가 있다고 가정 해 봅시다. 그러나 그것은 또한 실패 할 수 있으며, 그것이 언제인지 알아야합니다.

어느 것이 더 좋은 방법입니까?

public int? DoSomethingWonderful()

또는

public bool DoSomethingWonderful(out int parameter)

이것은 아마도 스타일의 질문 일 것입니다. 그러나 사람들이 어떤 옵션을 취할 것인지 궁금합니다.

편집 : 설명,이 코드는 블랙 박스와 대화합니다 (클라우드라고 부릅니다. 아니요, 블랙 박스. 아니요, 기다립니다. 클라우드. 예). 나는 신경 쓰지 않는다 실패했습니다. 유효한 가치가 있는지 여부를 알아야합니다.

도움이 되었습니까?

해결책

Null Coalesce 연산자를 사용할 수 있기 때문에 Nullable 버전을 더 좋아합니다. 그것에, 예를 들어 :

int reallyTerrible = 0;
var mightBeWonderful = DoSomethingWonderful() ?? reallyTerrible;

다른 팁

호출 코드가 어떻게 보일 것이라고 생각하는지에 따라 다릅니다. 그러므로 당신의 기능이 사용되는 것.

일반적으로 논쟁을 피해야합니다. 반면에, 다음과 같은 코드를 갖는 것이 좋을 수 있습니다.

int parameter;
if (DoSomething(out paramameter))
{
  // use parameter
}

귀중한 int가 있으면 다음과 같습니다.

int? result = DoSomething();
if (result != null)
{
  // use result
}

인수가 없기 때문에 이것은 다소 더 좋습니다. 그러나 함수가 성공했는지 결정하는 코드는 그다지 명백하지 않습니다.

다른 옵션이 있다는 것을 잊지 마십시오 : 예의를 사용하십시오. 기능이 실패한 경우에만이 작업을 수행하는 것이 실제로 예외적이고 일종의 오류 사례 인 경우에만이 작업을 수행하십시오.

try
{
  // normal case
  int result = DoSomething()
}
catch (SomethingFailedException ex)
{
  // exceptional case
}

예외의 한 가지 장점은 당신이 그것을 무시할 수 없다는 것입니다. 정상적인 경우도 구현하기에 직접적입니다. 예외적 인 경우를 무시할 수있는 경우 예외를 사용해서는 안됩니다.

편집하다: 언급하는 것을 잊었습니다. 예외의 또 다른 장점은 정보를 제공 할 수 있다는 것입니다. 작업이 실패했습니다. 이 정보는 예외 유형, 예외의 속성 및 메시지 텍스트에 의해 제공됩니다.

왜 예외를 던지지 않습니까?

.NET 라이브러리의 어떤 곳에서 사용 된 패턴을 따를 것입니다.

bool int.TryParse(string s, out value)
bool Dictionary.TryGetValue(T1 key, out T2 value)

그래서 나는 다음과 같이 말할 것이다.

public bool TryDoSomethingWonderful(out int parameter)

그것은 당신이하는 일에 실제로 달려 있습니다.

Null은 의미있는 대답입니까? 그렇지 않다면, 나는 선호합니다 bool TryDoSomethingWonderful(out int) 방법 호출. 이것은 프레임 워크와 일치합니다.

그러나 NULL이 의미있는 반품 값이면 int를 반환합니까? 말이된다.

성능이 주요 관심사가 아니라면 int 실패에 대한 예외를 던집니다.

전화가 성공하면 즉시 알아야하기 때문에 두 번째를 사용할 것입니다.

int x;
if( DoSomethingWonderful( out x ) )
{
    SomethingElse(x);
}

~보다

int? x = DoSomethingWonderful();
if( x.HasValue )
{
   SomethingElse(x.Value);
}

출력 매개 변수를 사용하는 것을 선호합니다. 제 생각에는 이것은 출력 매개 변수의 사용이 가장 적합한 상황입니다.

예, Coalesce 연산자를 사용하여 나머지 코드에서 사용할 수있는 대체 값이있는 경우에만 코드를 1 라이너로 유지할 수 있습니다. 나는 종종 그것이 나에게는 그렇지 않다는 것을 알게되며, 값을 성공적으로 검색 할 수 있다면 다른 코드 경로를 실행하는 것을 선호합니다.

        int value;
        if(DoSomethingWonderful(out value))
        {
            // continue on your merry way
        }
        else
        {
            // oops
            Log("Unable to do something wonderful");

            if (DoSomethingTerrible(out value))
            {
                // continue on your not-so-merry way
            }
            else
            {
                GiveUp();
            }
        }

또한 검색하려는 값이 실제로 무효화 할 수있는 경우 출력 매개 변수와 부울 리턴 값이있는 함수를 사용하는 것은 "값을 검색하는 데 실패했습니다"의 차이를 말하는 가장 쉬운 방법입니다. 그리고 "내가 검색 한 값은 null"입니다. 때때로 나는 다음 예에서와 같이 그 차이에 관심이 있습니다.

    private int? _Value;
    private bool _ValueCanBeUsed = false;

    public int? Value
    {
        get { return this._Value; }
        set
        {
            this._Value = value;
            this._ValueCanBeUsed = true;
        }
    }

    public bool DoSomethingTerrible(out int? value)
    {
        if (this._ValueCanBeUsed)
        {
            value = this._Value;
            // prevent others from using this value until it has been set again
            this._ValueCanBeUsed = false;
            return true;
        }
        else
        {
            value = null;
            return false;
        }
    }

제 생각에, 대부분의 사람들이 출력 매개 변수를 사용하지 않는 유일한 이유는 구문이 번거 롭다는 것입니다. 그러나 나는 출력 매개 변수를 사용하는 것이이 문제에 대한 더 적절한 솔루션이라고 생각하며, 일단 익숙해지면 구문이 널 값을 반환하는 것이 훨씬 바람직하다는 것을 알았습니다.

실패 할 수있는 방법이 하나만 있거나 알 필요가 없다면 실패했습니다. 나는 무효가 불가능한 반환 값으로 가기가 더 단순하고 쉽다고 말할 것입니다.

반대로, 실패 할 수있는 여러 가지 방법이 있고 호출 코드가 왜 실패한 이유를 정확히 알고 싶다면, OUT 매개 변수로 이동하여 BOOL 대신 오류 코드를 반환합니다 (또는 예외를 기반으로 할 수 있습니다. 귀하의 질문에, 이미 예외를 던지지 않기로 결정한 것 같습니다).

오히려 시도 캐치를 사용해야합니다. 발신자가 무슨 일이 일어날 지 모르는 것 같습니다.

bool과 out을 모두 확인하거나 반품 Null과 실제 반환을 모두 확인해야합니다.

이 방법이해야 할 일을하고 실패한 경우 발신자에게 실패했음을 알리고 발신자 Hanlde가 요청한대로 알려주십시오.

흥미롭게도 내 개인적인 의견은 방법의 본질에 따라 크게 흔들립니다. 구체적으로, 방법의 목적이 있다면 단일 값을 검색합니다, "무언가를하는 것"에 반대하는 것.

전:

bool GetSerialNumber(out string serialNumber)

vs

string GetSerialNumber() // returns null on failure

두 번째는 어떻게 든 나에게 더 "자연스러운"느낌이 들었습니다.

bool GetDeviceId(out int id)

vs

int? GetDeviceId() // returns null on failure`

그러나 나는 이것이 실제로 "코딩 스타일"영역에 속한다는 것을 인정합니다.

아, 나도 예외 던지기를 선호하는 경향이 있습니다.

int GetDeviceId() // throws an exception on read failure

나는 왜 그들이 왜 그렇게 잘못되었는지에 대해 팔리지 않았다. 오렌에 실을 가질 수 있습니까? ;-)

"Out"매개 변수가 데이터 항목을 반환하는 데 사용되는 Microsoft의 "Try"패턴을 싫어합니다. 무엇보다도, 그 방식으로 코딩 된 방법은 공분산 인터페이스에서 사용할 수 없습니다. 차라리 코딩 된 메소드를 볼 수 있습니다. T GetValue(out bool Successful) 아니면 아마도 T GetValue(out GetValueErrorEnum result); 또는 T GetValue(out GetValueErrorInfo result); 참/거짓 이외의 것이 필요한 경우. 모든 데이터 유형에는 법적 기본값이 있으므로 함수가 실패하면 반환 할 내용을 결정하는 데 아무런 문제가 없습니다. 통화 코드는 쉽게 말할 수 있습니다.

  bool success;
  var myValue = Thing.GetValue(ref success);
  if (success)
    .. do something using myValue
  else
    .. ignore myValue

.NET과 C#이 진정한 공분산 '복사'매개 변수를 제공 한 경우 좋을 것입니다 (발신자는 결과를위한 공간을 할당하고 해당 공간에 대한 포인터를 호출 된 함수로 전달한 다음 할당 된 공간을 전달 된 변수에 복사합니다. 함수가 반환 된 후에 만).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top