2017-09-22 15 views
0

두 가지 질문이 있으며 도움이 필요합니다.유효한/존재하는 값을 확인할 때 Nullable 대 Out 매개 변수

시간이 지남에 따라 변하는 변수/값에 액세스해야하는 클라이언트 코드가 있으며 실제로는 검색시 계산되며 런타임에 여러 번 여러 방법으로 검색되지만 계산은 그렇지 않습니다. 항상 그 요구 사항이 항상 존재하는 것은 아니므로 항상 거짓 또는 null이 반환되고 클라이언트가이를 확인하여 계속 진행할 것인지 결정합니다. 자, 두 가지 접근 방법이 있습니다. 첫 번째는 입니다. 제 고전의 하나입니다. B 그러나 나에게도 좋을 것 같습니다.

A)는 좀 C#을 라이브러리에 TryParse 방법과 유사한 출력 매개 변수를 사용하여이 방법을 가지고 :

public bool GetLeadingTrailSegment(out Vector3 lastTrailSegment) 
{ 
    if (_line.positionCount > 1) 
    { 
     lastTrailSegment = lead - _line.GetPosition(_line.positionCount - 2); 
     return true; 
    } 
    lastTrailSegment = Vector3.zero; 
    return false; 
} 

B) 나는 같은 일을하려고이 널 (NULL) 속성이 위의 코드는 다음과 같이

public Vector3? leadingTrailSegment 
{ 
    get 
    { 
     if (_line.positionCount > 1) 
     { 
      return lead - _line.GetPosition(_line.positionCount - 2); 
     } 
     return null; 
    } 
} 

클라이언트 코드는 다음과 같습니다

A) 여기서 bool은 클라이언트 코드가 값을 사용할 때 안전 (유용할까요?)인지 알려줍니다. 이 안전 어떠했는지

public bool IsDrawingOverAllowed(LayoutPointer pointer) 
{ 
    Vector3 leadingTrailSegment; 
    if (pointer.GetLeadingTrailSegment(out leadingTrailSegment)) 
    { 
     return !midline.ParallelTo(leadingTrailSegment); 
    } 
    return true; 
} 

B) 여기가 거짓 인 널 (NULL)의 HasValue 속성의 사실은 클라이언트를 알려줍니다

public bool IsDrawingOverAllowed(LayoutPointer pointer) 
{ 
    Vector3? leadingTrailSegment = pointer.leadingTrailSegment; 
    if (leadingTrailSegment.HasValue) 
    { 
     return !midline.ParallelTo(leadingTrailSegment.Value); 
    } 
    return true; 
} 

첫 번째 질문 :이 두 가지 방법 중, 어떤 것이 가장 좋습니까? 아니면 그들 사이에 찬반 양론이 있습니까?

두 번째 질문 :

public bool IsDrawingOverAllowed(LayoutPointer pointer) 
{ 
    if (pointer.leadingTrailSegment.HasValue) 
    { 
     return !midline.ParallelTo(pointer.leadingTrailSegment.Value); 
    } 
    return true; 
} 

이 잘, 잘못 : 나는대로 쓴 클라이언트 B 접근을하는 데 사용? nullable의 Value 속성이 두 번째 호출에 의해 변경되었을 수 있기 때문입니다.

저는 out 매개 변수 접근법을 가장 좋아합니다. if 절에서 결과를 사용할 수 있으며 다른 버전의 C#에서 변수를 인라인으로 선언 할 수도 있지만 nullable에 대한 샷을 제공하고 싶습니다 이와 같은 상황에서 유용합니다 (할당되지 않은 값을 찾을 때뿐만 아니라 내가 사용하는 경우). 나는 누군가가 이것에 대한 그들의 생각을 줄 수 있기를 바랍니다.

감사합니다.

+0

두 번째 질문에 'Vector3? 당신이 다른 지역에있는'Vector3?'를 복사 한 후에는'if (segment.HasValue)'와'return! midline.ParallelTo (segment.Value); ' 불변의 구조체이기 (위해) 때문에,보다 긴 변경이 필요합니다. –

+0

제 추측이 맞았습니까? 나는 클라이언트의 B 접근법에 위의 한 예를 썼기 때문에 그렇게했다. 감사. – Ruri

+0

예, 첫 번째 질문에서 B가 더 나은 방법 일 것입니다. 또한 태그가 잘못되었습니다. 'C# -4.0'은 .NET 4.0이 아닙니다. 2017.1.0 현재 Unity3d C# 6을 지원합니다. –

답변

4

출력 매개 변수를 사용하는 것보다 null을 반환하는 호출을 선호합니다. 출력 매개 변수는 개인적으로 정말로 싫어하는 종류의 "부작용"경향이있는 코드 구조입니다. 이것은 호출 코드가 사용하기 전에 변수를 정의해야한다는 것을 의미하며 우연히 잘못된 변수를 호출하면 버그를 유발하기 쉬운 취약점이 있음을 의미합니다. 또한 널 조건부 및 널 통합 연산자가있는 호출 체인에서 코드를 사용할 수 없도록합니다. var v = GetLeadingTrailSegment() ?? new Vector3();과 같은 것을 할 수 없습니다.

두 번째 주목할 점은 Nullable 사용입니다. Vector3 유형이 값 유형이면 괜찮습니다. 그것이 참조 형식 (.NET의 필수 유형 및 구조 이외의 모든 것)이라면 필요하지 않습니다. 단지 return null;if (variable != null) { ... }입니다. bool을 반환하는 경우는 대개 반환 값 충돌이있는 경우입니다. 예를 들어, null가 그 자체로 유효한 값으로서 돌려 주어 졌을 경우, 유효한 null 또는 무효 인 응답을 구별하는 방법이 필요했습니다. 여기서는 그렇지 않습니다.

+0

'out '을 사용할 때의 부작용에 동의하지만 어떤 경우에는 매우 편리하다고 생각합니다. 'Physics.Raycast()'는 하나입니다. 오버로드 중 일부는 'out'매개 변수를 갖지 않습니다. ['if (Physics.Raycast (transform.position, fwd, 10)) {...}'] (https://docs.unity3d.com/ScriptReference/Physics.Raycast.html) 그리고 여기 * null * * 감각을 내기도한다. (그래서 리턴은 부울이고 아웃 오브젝트는 부작용이다) – Draco18s

0

내 두 센트 :

tldr : 당신은 부울을 반환하는 방법을 갖고 싶어하지만 이름이 다른 일을하시기 바랍니다

차라리 물어 ​​것입니다.


플레이어에 player.GetCurrentHp()이 있고 플레이어에 hp 또는 hp == 0이없는 경우이 메서드가 false를 반환하면 이름이 잘못 알려 졌으므로 player.isAlive() 메서드를 사용하는 것이 좋습니다.

논리 또는 소프트웨어 관점에서 본질적으로 잘못된 것이 아니지만 다음 개발자가 해당 코드로 작업하거나 6 개월 만에 작업하는 데 도움이되지 않습니다.

귀하의 경우에는 LayoutPointer에 대해 두 가지 방법을 사용합니다.

public bool IsValid() // <--- I like when boolean methods represent 'is, can, have' actions, ideas, or properties. 
{ 
    return _line.positionCount > 1; 
} 

public bool GetLeadingTrailSegment() 
{ 
    if (!IsValid()) 
    { 
     return Vector3.zero; 
    } 

    return (lead - _line.GetPosition(_line.positionCount - 2)); 
} 

그리고;

public bool IsDrawingOverAllowed(LayoutPointer pointer) 
{ 
    if (pointer == null) 
    { 
     Debug.LogWarning("IsDrawingOverAllowed: Pointer is null!"); 
     return true; // or false, it depends on your design.. 
    } 

    if (!pointer.IsValid()) // <-- I also like early returns :D 
    { 
     return true; 
    } 

    var leadingTrailSegment = pointer.GetLeadingTrailSegment() 
    return !midline.IsParallelTo(leadingTrailSegment); 
} 

나는 당신이 읽기 쉬운 몇 가지 코드를 갖고 싶어 말, 이해 .. 그보다 '자세한 정보'할 수 있지만 기계 코드는 간단하지만, 인간에 대한 코드가 어렵 만들 생각을 기억할 수있어 유지하라.

사이드 노트; 네, 때로는 유용 할 수 있습니다. 예를 들어, Physics.Raycast처럼 유용 할 수도 있지만, 만약 당신이 TryParse pattern을 구현하지 않는다면 (예를 들어 try/catch를 사용하지 않기를 원한다면) 두 가지 일을하는 한 가지 방법 만 시도해 볼 수는 없습니다. .