마법 값을 반환하거나 예외를 던지거나 실패시 거짓을 반환합니까?


83

때로는 실제 답변이없는 것이 예외가 아닌 클래스 라이브러리에 대한 메소드 또는 속성을 작성 해야하는 경우가 있습니다. 확인할 수 없거나 사용할 수 없거나 찾을 수 없거나 현재 사용할 수 없거나 더 이상 사용할 수있는 데이터가 없습니다.

C # 4에서 실패를 나타내는 비교적 예외적이지 않은 상황에 대한 세 가지 가능한 솔루션이 있다고 생각합니다 .

  • 다른 의미가없는 마술 값을 반환합니다 (예 : null-1).
  • 예외를 던지십시오 (예 :) KeyNotFoundException;
  • 되돌아 false와의 실제 반환 값을 제공하는 out매개 변수를 (예컨대 Dictionary<,>.TryGetValue).

따라서 질문은 다음 같습니다. 예외가 아닌 상황에서 예외를 던져야합니까? 그리고 내가 던져서는 안되는 경우 : 언제 매개 변수 로 Try*메소드를 구현하는 것보다 마법의 가치를 반환out 합니까? 나에게 out매개 변수가 더러워 보이며 올바르게 사용하는 것이 더 많은 작업입니다.

디자인 지침 ( Try*메소드 에 대해 전혀 모른다 ), 유용성 (클래스 라이브러리에 대해 요청), BCL과의 일관성 및 가독성과 같은 사실적인 답변을 찾고 있습니다.


.NET Framework 기본 클래스 라이브러리에서는 세 가지 방법이 모두 사용됩니다.

로합니다 HashtableC #에서 더 제네릭 없었다 시점에서 만든, 그것은 사용 object하기 때문에 반환 할 수 있습니다 null마법의 값으로. 그러나 제네릭의 경우 예외가에서 사용 Dictionary<,>되며 처음에는 예외가 없었습니다 TryGetValue. 분명히 통찰력이 바뀝니다.

물론, Item- TryGetValueParse- TryParse이중성은 이유가있다, 그래서 나는 비 뛰어난 실패에 대한 예외를 던지는 C # 4에 있다고 가정 하지 . 그러나 Try*방법이 존재하더라도 항상 존재하는 것은 아닙니다 Dictionary<,>.Item.


6
"예외는 버그를 의미한다". 존재하지 않는 항목에 대한 사전을 요청하는 것은 버그입니다. EOF 일 때 데이터를 읽도록 스트림에 요청하면 스트림을 사용할 때마다 발생합니다. (이 : 내가 제출 기회를 얻지 않았다 긴 아름답게 형식의 대답을 요약)
KutuluMike

6
귀하의 질문이 너무 광범위하다고 생각되는 것이 아니라 건설적인 질문이 아닙니다. 답변이 이미 표시되어 있기 때문에 정식 답변이 없습니다.
George Stocker

2
@GeorgeStocker 대답이 간단하고 명백하다면 질문을하지 않았을 것입니다. 사람들이 어떤 선택 (성능, 가독성, 유용성, 유지 관리 성, 설계 지침 또는 일관성과 같은)에서 주어진 선택이 바람직한 이유를 주장 할 수 있다는 사실은 본질적으로 비정규 적이지만 내 만족에 대답 할 수 있습니다. 모든 질문은 다소 주관적으로 대답 할 수 있습니다. 분명히 당신은 질문이 좋은 질문이되기 위해 대부분 비슷한 대답을 가질 것으로 기대합니다.
Daniel AA Pelsmaeker

3
@Virtlink : George는 커뮤니티에서 선출 된 중재자로 Stack Overflow를 유지하는 데 많은 시간을 할애합니다. 그는 왜 질문을 닫았으며 FAQ는 그를 뒷받침합니다.
Eric J.

15
문제는 주관적이기 때문에가 아니라 개념 이기 때문에 여기에 속합니다 . 경험 법칙 : IDE 코딩 앞에 앉아 있다면 스택 오버플로에 문의하십시오. 화이트 보드 브레인 스토밍 앞에 서 있다면 프로그래머에게 문의하십시오.
Robert Harvey

답변:


56

나는 당신의 예제가 실제로 동등한 것이라고 생각하지 않습니다. 세 가지 그룹이 있으며 각 그룹은 각자의 행동에 대한 자신의 이론적 근거가 있습니다.

  1. 매직 값은 "완료"조건과 같은 경우 StreamReader.Read또는 유효한 답이 될 수없는 사용하기 쉬운 값이있을 때 좋은 옵션입니다 (-1의 경우 IndexOf).
  2. 함수의 의미론에서 호출자가 작동 할 것이라고 확신하는 경우 예외를 처리하십시오. 이 경우 존재하지 않는 키 또는 잘못된 이중 형식은 정말 예외적입니다.
  3. 연산이 가능한지 여부에 대한 의미가 프로브되는 경우 출력 매개 변수를 사용하고 부울을 리턴하십시오.

제공하는 예제는 사례 2와 3에 대해 완벽하게 명확합니다. 마법 값의 경우 이것이 좋은 디자인 결정인지 또는 모든 경우에 해당되지 않는지 논쟁 할 수 있습니다.

NaN의해 반환되는 Math.Sqrt것은 특별한 경우입니다-부동 소수점 표준을 따릅니다.


10
숫자 1에 동의하지 않습니다. 매직 값은 다음 코더가 매직 값의 중요성을 알아야하기 때문에 좋은 옵션이 아닙니다. 또한 가독성을 떨어 뜨립니다. 마술 패턴을 사용하는 것이 Try 패턴보다 나은 경우는 없다고 생각할 수 있습니다.
0b101010

1
그러나 Either<TLeft, TRight>모나드는 어떻습니까?
sara

2
@ 0b101010 : streamreader.read가 안전하게 -1을 반환 할 수있는 방법을 찾는 데 시간을 보냈습니다.
jmoreno

33

API 사용자에게해야 할 일을 전달하려고합니다. 예외를 던지면 예외를 잡을 필요가 없으며 문서를 읽는 것만으로 모든 가능성을 알 수 있습니다. 개인적으로 특정 방법으로 발생할 수있는 모든 예외를 찾기 위해 문서를 파헤치는 것이 느리고 지루합니다.

매직 값은 여전히 ​​문서를 읽고 const값을 해독하기 위해 일부 테이블을 참조 해야합니다. 적어도 예외가 아닌 발생이라고 부르는 예외에 대한 오버 헤드는 없습니다.

그렇기 때문에 out때로는 매개 변수가 찌그러 지더라도 Try...구문 이있는 해당 방법을 선호 합니다. 표준 .NET 및 C # 구문입니다. API 사용자에게 결과를 사용하기 전에 반환 값을 확인해야한다는 내용을 전달하고 있습니다. out유용한 오류 메시지와 함께 두 번째 매개 변수를 포함시켜 디버깅에 다시 도움을 줄 수도 있습니다. 이것이 Try...with out매개 변수 솔루션에 투표하는 이유 입니다.

또 다른 옵션은 특별한 "결과"객체를 반환하는 것입니다.

interface IMyResult
{
    bool Success { get; }
    // Only access this if Success is true
    MyOtherClass Result { get; }
    // Only access this if Success is false
    string ErrorMessage { get; }
}

그런 다음 입력 매개 변수 만 있고 하나만 반환하기 때문에 함수 올바르게 보입니다 . 그것이 반환하는 것은 일종의 튜플 일뿐입니다.

사실, 당신이 그런 종류의 일에 빠져 있다면, Tuple<>.NET 4에 도입 된 새로운 클래스를 사용할 수 있습니다 . 개인적으로 나는 각 필드의 의미가 줄 수 없기 때문에 덜 명확하다는 사실을 좋아하지 않습니다 Item1Item2유용한 이름.


3
개인적으로, 나는 종종 당신의 IMyResult원인 과 같은 결과 컨테이너를 사용 합니다. 단지 true또는 false결과 값 보다 더 복잡한 결과를 전달할 수 있습니다. Try*()string to int 변환과 같은 간단한 것들에만 유용합니다.
this.myself 2012 년

1
좋은 소식입니다. 필자는 "반환"값과 "출력"매개 변수를 나누는 대신 위에서 설명한 결과 구조 관용구를 선호합니다. 깔끔하고 깔끔하게 유지합니다.
Ocean Airdrop

2
두 번째 매개 변수의 문제점은 복잡한 프로그램에서 50 개의 기능을 사용할 때 오류 메시지를 사용자에게 다시 전달하는 방법입니다. 예외를 던지는 것은 오류 검사 계층보다 훨씬 간단합니다. 당신이 하나를 얻을 때 그냥 던져 당신이 얼마나 깊이 중요하지 않습니다.

@rolls-출력 객체를 사용할 때 즉시 호출자가 출력으로 원하는 것을 수행한다고 가정합니다. 로컬로 처리하거나 무시하거나 예외로 래핑하여 버블 링합니다. 두 단어 중 가장 좋습니다-호출자는 가능한 모든 출력 (enum 등)을 명확하게 볼 수 있으며 오류와 관련된 작업을 결정할 수 있으며 각 호출에서 catch를 시도 할 필요가 없습니다. 대부분 결과를 즉시 처리하거나 무시할 것으로 예상되는 경우 반환 객체가 더 쉽습니다. 모든 오류를 상위 계층에 던지려면 예외가 더 쉽습니다.
drizin

2
이것은 Java에서 확인 된 예외보다 훨씬 지루한 방식으로 C #에서 확인 된 예외를 재발 명합니다.
Winter

17

귀하의 예가 이미 보여 주듯이, 각각의 경우는 개별적으로 평가되어야하며, 특히 예외적 인 상황과 흐름 제어 사이에 상당한 회색 스펙트럼이 있으며, 특히 귀하의 방법을 재사용 할 수 있고 매우 다른 패턴으로 사용될 수있는 경우 원래 설계된 것보다 특히 "예외"를 사용하여이를 구현할 수있는 가능성에 대해 즉시 논의하는 경우 "비 예외적"의 의미에 동의하지 마십시오.

우리는 또한 어떤 디자인이 코드를 읽고 유지하기 가장 쉬운 지에 대해서는 동의하지 않을 수도 있지만, 라이브러리 디자이너는 그에 대한 명확한 개인적인 비전을 가지고 있으며 관련된 다른 고려 사항과 균형을 맞출 필요가 있다고 가정합니다.

짧은 답변

매우 빠른 방법을 설계하고 예기치 않은 재사용 가능성을 예상 할 때를 제외하고는 장의 감정을 따르십시오.

긴 대답

미래의 각 발신자는 양방향에서 원하는대로 오류 코드와 예외를 자유롭게 변환 할 수 있습니다. 따라서 성능, 디버거 친 화성 및 일부 제한된 상호 운용성 컨텍스트를 제외하고 두 가지 디자인 방식이 거의 동일합니다. 일반적으로 성능이 저하되므로 이에 초점을 맞추겠습니다.

  • 경험상 예외를 던지는 것이 정규 수익보다 200 배 더 느릴 것으로 예상하십시오 (실제로 상당한 차이가 있습니다).

  • 경험상, 예외를 던지면 프로그래머가 오류 코드를 다른 오류 코드로 변환하는 프로그래머에 의존하지 않기 때문에 대부분의 마법 값에 비해 훨씬 깨끗한 코드를 허용 할 수 있습니다. 일관성 있고 적절한 방식으로 처리하기에 충분한 컨텍스트가있는 지점. (특별한 경우 : 일부 유형의 결함이 아닌 일부 유형의 경우 null자동으로 변환되는 경향이 있기 때문에 다른 마법 값보다 더 나은 경향이 NullReferenceException있습니다. )

교훈은 무엇입니까?

응용 프로그램 수명 동안 (응용 프로그램 초기화와 같이) 몇 번만 호출되는 함수의 경우 코드를 더 명확하고 이해하기 쉽게하는 것을 사용하십시오. 성능은 문제가되지 않습니다.

버리기 기능의 경우 코드를 더 깨끗하게하는 것을 사용하십시오. 그런 다음 프로파일 링 (필요한 경우)을 수행하고 측정 또는 전체 프로그램 구조를 기반으로 의심되는 최상위 병목 현상이 발생하면 예외를 반환하여 코드를 반환하십시오.

값 비싼 재사용 가능한 기능을 위해서는 더 깨끗한 코드를 제공하는 것을 사용하십시오. 기본적으로 항상 네트워크 왕복을 수행하거나 디스크상의 XML 파일을 구문 분석해야하는 경우 예외를 발생시키는 오버 헤드는 무시할 수 있습니다. "예외가 아닌 실패"에서 더 빨리 돌아가는 것보다 실수로 실패하지 않은 세부 정보를 잃지 않는 것이 더 중요합니다.

마른 재사용 기능에는 더 많은 생각이 필요합니다. 예외를 사용 하면 함수 본문이 매우 빠르게 실행되는 경우 (많은) 호출의 절반에서 예외를 볼 수있는 호출자에게 100 배의 속도 저하를 강요 합니다. 예외는 여전히 설계 옵션이지만이를 감당할 수없는 발신자에게는 낮은 오버 헤드 대안을 제공해야합니다. 예를 봅시다.

Dictionary<,>.Item느슨하게 말해서 null값을 반환하는 것에서 KeyNotFoundException.NET 1.1과 .NET 2.0 사이의 던지기 로 바뀌는 훌륭한 예를 나열합니다 ( Hashtable.Item실제로 제네릭이 아닌 선구자 로 간주하려는 경우에만 ). 이 "변경"의 이유는 여기에 관심이 없습니다. 값 유형의 성능 최적화 (더 이상 복싱 없음)는 원래의 마법 값 ( null)을 옵션이 아닌 것으로 만들었습니다 . out매개 변수는 성능 비용의 작은 부분을 다시 가져옵니다. 후자의 성능 고려 사항은 을 던지는 오버 헤드와 비교할 때 완전히 무시할 수KeyNotFoundException 있지만 예외 디자인은 여전히 ​​우수합니다. 왜?

  • ref / out 매개 변수는 "실패"사례뿐만 아니라 매번 비용이 발생합니다.
  • 관심있는 사람 Contains은 인덱서에 대한 호출 전에 호출 할 수 있으며이 패턴은 자연스럽게 읽습니다. 개발자가 호출을 잊고 싶지만 Contains성능 문제가 발생할 수는 없습니다. KeyNotFoundException눈치 채고 고칠 정도로 시끄 럽습니다.

나는 200x가 예외의 성능에 대해 낙관적이라고 생각한다 ... 코멘트 바로 전에 blogs.msdn.com/b/cbrumme/archive/2003/10/01/51524.aspx "성능과 트렌드"섹션을 참조하십시오 .
gbjbaanb

@gbjbaanb-글쎄요. 이 기사는 1 %의 실패율을 사용하여 완전히 다른 야구장이 아닌 주제를 논의합니다. 내 자신의 생각과 막연하게 기억 측정 테이블 구현 C의 문맥에서 것 ++ (제 5.4.1.2 볼 이 보고서 과감한 변수 하나의 문제는 최초의 예외가 페이지 폴트로 시작 가능성이 있다는 것입니다, ( 그러나 한 번의 오버 헤드를
상실했습니다

ref / out 매개 변수의 비용 이 높은가 ? 어떻게 요? 그리고 Contains인덱서 호출 전에 호출하면 경쟁 조건이 없어도됩니다 TryGetValue.
Daniel AA Pelsmaeker

@gbjbaanb-실험 완료. 나는 게으르고 리눅스에서 모노를 사용했다. 예외 는 3 초 만에 ~ 563000의 던졌습니다. 반품 은 3 초 안에 ~ 10900000의 반품을 받았습니다. 1:20이 아니라 1 : 200입니다. 더 현실적인 코드를 위해 1 : 100 이상을 생각하는 것이 좋습니다. (내가 예상 한대로 out 매개 변수는 무시할만한 비용을 가졌다. 실제로 서명에 관계없이 예외가 발생하지 않으면 지터가 최소한의 예제에서 콜을 완전히 최적화했다고 생각한다.)
Jirka Hanika

@Virtlink-일반적으로 스레드 안전성에 동의하지만 특히 .NET 4를 언급 한 ConcurrentDictionary경우 멀티 스레드 액세스 및 Dictionary최적의 성능을위한 단일 스레드 액세스에 사용하십시오. 즉,``포함 ''을 사용하지 않으면이 특정 Dictionary클래스 에서 코드 스레드를 안전하게 만들 수 없습니다 .
Jirka Hanika

10

상대적으로 예외적이지 않은 상황에서 실패를 나타내는 최선의 방법은 무엇입니까?

실패를 허용해서는 안됩니다.

나는 손이 흔들리고 이상적이지만 내 말을 듣는다. 디자인을 수행 할 때 실패 모드가없는 버전을 선호하는 경우가 많이 있습니다. LINQ는 실패한 'FindAll'대신에 빈 열거 형을 반환하는 where 절을 사용합니다. 사용하기 전에 초기화해야하는 객체를 갖는 대신 생성자가 객체를 초기화하도록합니다 (또는 초기화되지 않은 것이 감지되면 초기화). 핵심은 소비자 코드에서 실패 분기를 제거하는 것입니다. 이것이 문제이므로 집중하십시오.

이를위한 또 다른 전략은 KeyNotFound시나리오입니다. 3.0 이후로 작업 한 거의 모든 코드베이스에는 다음과 같은 확장 방법이 있습니다.

public static class DictionaryExtensions {
    public static V GetValue<K, V>(this IDictionary<K, V> arg, K key, Func<K,V> ifNotFound) {
        if (!arg.ContainsKey(key)) {
            return ifNotFound(key);
        }

        return arg[key];
    }
}

이에 대한 실제 실패 모드는 없습니다. ConcurrentDictionary비슷한 GetOrAdd내장되어 있습니다.

그러나 피할 수없는 경우가 항상 있습니다. 세 사람 모두 자리가 있지만 첫 번째 옵션을 선호합니다. 널 (null)의 위험으로 만들어진 모든 것에도 불구하고, 그것은 잘 알려져 있으며 "예외가 아닌"세트를 구성하는 많은 '항목을 찾을 수 없음'또는 '결과가 적용되지 않습니다'시나리오에 적합합니다. 특히 nullable 값 형식을 만들 때 '이것이 실패 할 수 있습니다'의 중요성은 코드에서 매우 명시 적이며 잊어 버릴 수 없습니다.

두 번째 옵션은 사용자가 바보 같은 일을 할 때 충분합니다. 잘못된 형식의 문자열을 제공하고 날짜를 12 월 42 일로 설정하려고 시도합니다. 테스트 중에 잘못된 코드가 식별되고 수정되도록 신속하고 훌륭하게 날려 버리고 싶은 것입니다.

마지막 옵션은 점점 싫어하는 옵션입니다. 아웃 매개 변수는 어색하며 한 가지에 집중하고 부작용이없는 방법을 만들 때 모범 사례 중 일부를 위반하는 경향이 있습니다. 또한 out 매개 변수는 일반적으로 성공하는 동안에 만 의미가 있습니다. 즉, 일반적으로 동시성 문제 또는 성능 고려 사항 (예 : DB로 두 번째 여행을 원하지 않는 경우)으로 제한되는 특정 작업에 필수적입니다.

반환 값과 출력 매개 변수가 사소한 것이 아니라면 결과 개체에 대한 Scott Whitlock의 제안이 선호됩니다 (예 : Regex Match클래스).


7
애완 동물 out은 여기에 있습니다 : 매개 변수는 부작용 문제와 완전히 직교합니다. ref매개 변수 수정 은 부작용이며 입력 매개 변수를 통해 전달한 객체의 상태를 수정하는 것은 부작용이지만 out매개 변수는 함수가 둘 이상의 값을 반환하도록하는 어색한 방법입니다. 부작용은 없으며 여러 개의 반환 값만 있습니다.
Scott Whitlock

사람들이 사용하는 방식 때문에 나는 경향이 있다고 말했다 . 당신이 말했듯이, 그들은 단순히 여러 개의 반환 값입니다.
Telastyn

그러나 매개 변수를 싫어하고 예외를 사용하여 형식이 잘못되었을 때 놀라운 일을 처리하면 형식이 사용자 입력 인 경우를 어떻게 처리합니까? 그런 다음 사용자가 일을 폭파 시키거나 예외를 던지고 잡는 경우 성능 저하가 발생합니다. 권리?
Daniel AA Pelsmaeker

고유 한 검증 방법을 사용하여 @virtlink. 당신은 필요 어쨌든 그들은 그것을 제출하기 전에 UI에 적절한 메시지를 제공합니다.
Telastyn

1
출력 매개 변수에 대한 올바른 패턴이 있으며 이는 다른 유형을 리턴하는 과부하가있는 함수입니다. 오버로드 분석은 리턴 유형에는 작동하지 않지만 매개 변수에 대해서는 작동합니다.
Robert Harvey

2

항상 예외를 던지는 것을 선호합니다. 그것은 실패 할 수있는 모든 기능들 사이에 균일 한 인터페이스를 가지고 있으며, 가장 바람직한 특성 인 실패를 가능한 한 시끄럽게 나타냅니다.

그 주 ParseTryParse정말 고장 모드에서 떨어져 같은 것이 아니다. TryParse값을 반환 할 수 있다는 사실은 실제로 직교합니다. 예를 들어 일부 입력의 유효성을 검사하는 상황을 고려하십시오. 값이 유효한 한 실제로 값을 신경 쓰지 않습니다. 그리고 일종의 IsValidFor(arguments)기능 을 제공하는 데 아무런 문제가 없습니다 . 그러나 절대 기본 작동 모드가 될 수는 없습니다 .


4
메소드에 대한 많은 호출을 처리하는 경우 예외는 성능에 큰 부정적인 영향을 줄 수 있습니다. 예외적 인 조건은 예외로 유지해야하며 양식 입력의 유효성 검사에는 완벽하게 수용 할 수 있지만 큰 파일의 숫자를 구문 분석 할 수는 없습니다.
Robert Harvey

1
일반적인 경우가 아니라보다 전문적인 요구입니다.
DeadMG

2
그래서 당신은 말합니다. 그러나 "항상"이라는 단어를 사용했습니다. :)
Robert Harvey

@DeadMG는 RobertHarvey와 동의했지만 답변이 과도하게 투표되었다고 생각하지만 "대부분의 시간"을 반영하도록 수정 된 다음 자주 사용되는 고성능과 관련하여 일반적인 경우에 대한 예외를 지적합니다. 다른 옵션을 고려하기 위해 전화.
Gerald Davis

예외는 비싸지 않습니다. 시스템이 스택을 가장 가까운 임계점으로 풀어야하기 때문에 깊게 던져진 예외를 잡아내는 것은 비용이 많이들 수 있습니다. 그러나 "고가"는 상대적으로 작으며 좁은 루프에서도 두려워해서는 안됩니다.
매튜 화이트

2

다른 사람들이 지적했듯이, 부울 리턴 값을 포함한 마술 값은 "범위 끝"마커를 제외하고는 그다지 큰 해결책이 아닙니다. 이유 : 오브젝트의 메소드를 검사하더라도 의미가 명시 적이 지 않습니다. 실제로 전체 개체에 대한 전체 설명서를 "오, 예 -42를 반환하면 bla bla bla"로 전체 문서를 읽어야합니다.

이 솔루션은 기록적인 이유로 또는 성능상의 이유로 사용될 수 있지만 피해야합니다.

이것은 두 가지 일반적인 경우를 남깁니다 : 조사 또는 예외.

여기서 경험의 규칙은 프로그램이 / 무의식적으로 / 일부 조건을 위반할 때 처리하는 것을 제외하고는 프로그램이 예외에 반응해서는 안된다는 것입니다. 이런 일이 발생하지 않도록 프로빙을 사용해야합니다. 따라서 예외는 관련 프로빙이 사전에 수행되지 않았거나 전혀 예상치 못한 일이 발생했음을 의미합니다.

예:

주어진 경로에서 파일을 작성하려고합니다.

이 경로가 파일 작성 또는 쓰기에 적합한 지 여부를 미리 평가하려면 File 객체를 사용해야합니다.

프로그램이 여전히 불법이거나 쓸 수없는 경로에 쓰려고 시도하는 경우, 탈출을해야합니다. 경쟁 조건으로 인해 발생할 수 있습니다 (일부 사용자가 디렉토리를 제거했거나 문제가 발생한 후 읽기 전용으로 만들었습니다).

예기치 않은 실패 (예외로 신호 처리)를 처리하고 사전에 작업에 적합한 조건 (프로빙)인지 확인하는 작업은 일반적으로 다르게 구성되므로 다른 메커니즘을 사용해야합니다.


0

Try코드가 일어난 일을 나타낼 때 패턴이 최선의 선택 이라고 생각합니다 . 나는 param을 싫어하고 nullable 객체를 좋아합니다. 나는 다음 수업을 만들었습니다.

public sealed class Bag<TValue>
{
    public Bag(TValue value, bool hasValue = true)
    {
        HasValue = hasValue;
        Value = value;
    }

    public static Bag<TValue> Empty
    {
        get { return new Bag<TValue>(default(TValue), false); }
    }

    public bool HasValue { get; private set; }
    public TValue Value { get; private set; }
}

그래서 다음 코드를 작성할 수 있습니다

    public static Bag<XElement> GetXElement(this XElement element, string elementName)
    {
        try
        {
            XElement result = element.Element(elementName);
            return result == null
                       ? Bag<XElement>.Empty
                       : new Bag<XElement>(result);
        }
        catch (Exception)
        {
            return Bag<XElement>.Empty;
        }
    }

nullable처럼 보이지만 값 유형뿐만 아니라

또 다른 예

    public static Bag<string> TryParseString(this XElement element, string attributeName)
    {
        Bag<string> attributeResult = GetString(element, attributeName);
        if (attributeResult.HasValue)
        {
            return new Bag<string>(attributeResult.Value);
        }
        return Bag<string>.Empty;
    }

    private static Bag<string> GetString(XElement element, string attributeName)
    {
        try
        {
            string result = element.GetAttribute(attributeName).Value;
            return new Bag<string>(result);
        }
        catch (Exception)
        {
            return Bag<string>.Empty;
        }
    }

3
try catchGetXElement()여러 번 전화 하고 실패 하면 성능에 혼란을 줄 것 입니다.
Robert Harvey

때때로 그것은 중요하지 않습니다. 가방 통화를 살펴보십시오. 관찰 해 주셔서 감사합니다

당신의 가방 <T> 제공자 라이선스 계약은 선택 System.Nullable 거의 동일 <T> "널 (NULL) 개체"일명
aeroson

예, public struct Nullable<T> where T : struct제약의 주요 차이점은 거의 없습니다 . 최신 버전은 여기 github.com/Nelibur/Nelibur/blob/master/Source/Nelibur.Sword/…
GSerjo

0

"마법의 가치"경로에 관심이 있다면이를 해결하는 또 다른 방법은 Lazy 클래스의 목적을 오버로드하는 것입니다. Lazy는 인스턴스화를 지연시키기위한 것이지만, 아마도 Like 또는 Option처럼 사용하는 것을 방해하는 것은 없습니다. 예를 들어 :

    public static Lazy<TValue> GetValue<TValue, TKey>(
        this IDictionary<TKey, TValue> dictionary,
        TKey key)
    {
        TValue retVal;
        if (dictionary.TryGetValue(key, out retVal))
        {
            var retValRef = retVal;
            var lazy = new Lazy<TValue>(() => retValRef);
            retVal = lazy.Value;
            return lazy;
        }

        return new Lazy<TValue>(() => default(TValue));
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.