입력이 기술적으로 유효하지만 만족할 수 없을 때 예외 대 빈 결과 집합


108

공개 릴리스 용 라이브러리를 개발 중입니다. 여기에는 집합을 생성, 검사, 분할 및 새로운 형태로 투영하는 다양한 개체 집합에 대한 다양한 방법이 포함되어 있습니다. 관련이있는 경우 IEnumerableNuGet 패키지로 릴리스되는 LINQ 스타일 확장이 포함 된 C # 클래스 라이브러리 입니다.

이 라이브러리의 일부 메소드에는 만족할 수없는 입력 매개 변수가 제공 될 수 있습니다. 예를 들어, 조합 방법에는 m 개의 소스 세트로부터 구성 될 수있는 n 개의 모든 세트의 세트를 생성하는 방법이 있다 . 예를 들어 다음과 같이 설정하면

1, 2, 3, 4, 5

2의 조합을 요청하면 다음이 생성됩니다.

1, 2
1, 3
1, 4
등 ...
5, 3
5, 4

이제 3 개 항목 세트를 제공 한 다음 4 개 항목의 조합을 요청하는 동안 각 항목을 한 번만 사용할 수 있다는 옵션을 설정하는 등 수행 할 수없는 작업을 요청할 수 있습니다.

이 시나리오에서 각 매개 변수는 개별적으로 유효합니다.

  • 소스 콜렉션이 널이 아니며 항목을 포함합니다.
  • 요청 된 조합 크기는 0이 아닌 양의 정수입니다.
  • 요청 된 모드 (각 항목을 한 번만 사용)는 올바른 선택입니다

그러나 매개 변수 상태를 합하면 문제가 발생합니다.

이 시나리오에서 메소드가 예외 (예 :)를 발생 InvalidOperationException시키거나 빈 콜렉션을 리턴 할 것으로 예상 하십니까? 나에게 유효한 것 같습니다 :

  • 각 항목을 한 번만 사용할 수 있으면 n> mm 항목 세트에서 n 항목의 조합을 생성 할 수 없으므로이 작업은 불가능한 것으로 간주 됩니다.InvalidOperationException
  • n> m 이 빈 세트 일 때 m 개의 아이템 으로부터 생성 될 수있는 크기 n 의 조합 세트; 조합을 만들 수 없습니다.

빈 세트에 대한 인수

첫 번째 관심사는 알 수없는 크기의 데이터 집합을 처리 할 때 예외로 인해 관용적 인 LINQ 스타일의 메서드 체인이 방지된다는 것입니다. 즉, 다음과 같은 작업을 수행 할 수 있습니다.

var result = someInputSet
    .CombinationsOf(4, CombinationsGenerationMode.Distinct)
    .Select(combo => /* do some operation to a combination */)
    .ToList();

입력 세트의 크기가 가변적이면이 코드의 동작을 예측할 수 없습니다. 경우 .CombinationsOf()경우 예외를 throw someInputSet미만의 4 개 요소를 가지고,이 코드는 것입니다 때로는 몇 가지 사전 검사없이 런타임에 실패합니다. 위의 예에서이 검사는 사소한 것이지만 더 긴 LINQ 체인을 반쯤 호출하면 지루할 수 있습니다. 빈 세트를 반환하면 비어 result있을 것입니다.

예외에 대한 논쟁

두 번째 관심사는 빈 세트를 반환하면 문제를 숨길 수 있다는 것입니다. LINQ 체인의 절반 아래에서이 메소드를 호출하고 빈 세트를 조용히 반환하면 몇 단계 후에 문제가 발생하거나 비어있는 것으로 스스로를 찾을 수 있습니다 결과 집합이 있고 입력 집합에 확실하게 무언가가있는 경우 어떻게 발생했는지 분명하지 않을 수 있습니다.

당신은 무엇을 기대하고 그것에 대한 당신의 주장은 무엇입니까?


66
빈 세트는 수학적으로 정확하기 때문에 얻을 때 실제로 원하는 것입니다. 수학적 정의와 관습은 일반적으로 일관성과 편의를 위해 선택되므로 문제가 해결됩니다.
asmeurer 2016

5
@asmeurer 이론 이 일관되고 편리 하도록 선택되었습니다 . 프로그래밍을 쉽게하기 위해 선택되지 않았습니다. (이것은 때로는 부수적 인 이점이지만 때로는 프로그래밍을 더 어렵게 만듭니다.)
jpmc26

7
@ jpmc26 "이론들은 일관성 있고 편리하도록 선택되었습니다"-프로그램이 항상 예상대로 작동하는지 확인하는 것은 본질적으로 정리 증명과 동일합니다.
artem

2
@ jpmc26 왜 함수형 프로그래밍을 언급했는지 모르겠습니다. 명령형 프로그램에 대한 정확성을 증명하는 것은 가능하고 항상 유리하며 비공식적으로도 가능합니다. 프로그램을 작성할 때 약간 생각하고 일반적인 수학적 의미를 사용하면 테스트 시간이 줄어 듭니다. 하나의 샘플에서 통계적으로 입증 됨 ;-)
artem

5
정의되지 않은 @DmitryGrigoryev 1/0은 무한대로 1/0보다 수학적으로 훨씬 정확합니다.
asmeurer

답변:


145

빈 세트 반환

다음과 같은 이유로 빈 세트를 기대합니다.

내가 각 숫자를 한 번만 사용할 수있는 경우 3 세트에서 4 개의 숫자 조합이 0입니다


5
수학적으로는 가능하지만 오류의 원인이기도합니다. 이 유형의 입력이 예상되면 사용자가 범용 라이브러리에서 예외를 포착하도록 요구하는 것이 좋습니다.
Casey Kuball

56
"아마도"오류의 원인이라는 데 동의하지 않습니다. 예를 들어, 지연 입력 세트에서 순진한 "matchmaknig"알고리즘을 구현했다고 가정합니다. 두 항목의 모든 조합을 요청하고 그 중 하나의 "최상의"일치 항목을 찾은 다음 두 요소를 모두 제거하고 더 작은 새 세트로 다시 시작할 수 있습니다. 결국 당신의 세트는 비어있을 것이고, 고려할 페어는 남아 있지 않을 것입니다 :이 시점에서의 예외는 방해입니다. 비슷한 상황에 처할 수있는 방법이 많이 있다고 생각합니다.
amalloy

11
실제로 사용자의 눈에 이것이 오류인지 알 수 없습니다. 빈 세트는 필요한 경우 사용자가 확인해야합니다. if (result.Any ()) DoSomething (result.First ()); else DoSomethingElse (); try {result.first (). dosomething ();} catch {DoSomethingElse ();}보다 훨씬 낫습니다
Guran

4
@TripeHound 결국 결정을 내리게 된 것입니다. 개발자가이 방법을 사용하여 확인한 다음 던지기를 요구하면 개발 노력, 프로그램 성능 및 관점에서 원하지 않는 예외를 던지는 것보다 훨씬 적은 영향을 미칩니다. 프로그램 흐름의 단순성.
anaximander

6
@Darthfett 기존 LINQ 확장 메서드 인 Where ()와 비교해보십시오. 절이있는 경우 : Where (x => 1 == 2) 예외가 발생하지 않으며 빈 세트가 나타납니다.
Necoras

79

확실하지 않은 경우 다른 사람에게 문의하십시오.

예제 함수는 Python과 매우 유사 itertools.combinations합니다. 그것이 어떻게 작동하는지 봅시다 :

>>> import itertools
>>> input = [1, 2, 3, 4, 5]
>>> list(itertools.combinations(input, 2))
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
>>> list(itertools.combinations(input, 5))
[(1, 2, 3, 4, 5)]
>>> list(itertools.combinations(input, 6))
[]

그리고 그것은 나에게 완벽하게 기분이 좋다. 나는 반복 할 수있는 결과를 기대하고 있었고 하나를 얻었다.

그러나, 당신이 어리석은 것을 요구한다면 분명히 :

>>> list(itertools.combinations(input, -1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: r must be non-negative

따라서 모든 매개 변수의 유효성이 검사되지만 결과가 빈 세트이면 빈 세트가 반환되면 유일한 방법은 아닙니다.


의견에서 @Bakuriu말했듯 이 이것은 같은 SQL쿼리 에서도 동일합니다 SELECT <columns> FROM <table> WHERE <conditions>. 만큼 <columns>, <table>, <conditions>잘 형성 및 기존 이름을 참조 형성되고, 당신은 서로를 배제하는 일련의 조건을 구축 할 수 있습니다. 결과 쿼리는를 던지는 대신 행을 생성하지 않습니다 InvalidConditionsError.


4
C # / Linq 언어 공간에서 관용적이지 않기 때문에 하향 투표 (언어에서 유사한 범위를 벗어난 문제를 처리하는 방법에 대한 sbecker의 답변 참조). 이것이 파이썬 질문이라면 그것은 +1 일 것입니다.
제임스 스넬

32
@JamesSnell 나는 그것이 범위를 벗어난 문제와 어떻게 관련되는지 거의 간신히 보았습니다. 우리는 요소를 재정렬하기 위해 인덱스별로 요소를 선택하지 않고 n컬렉션에서 요소를 선택하여 선택할 수있는 방법의 수를 계산합니다. 어떤 시점에서 요소를 선택하는 동안 남은 요소가 없으면 해당 n컬렉션에서 요소를 선택하는 방법이 없습니다 (0) .
Mathias Ettinger

1
여전히 파이썬은 C # 질문에 대한 좋은 오라클 1.0 / 0이 아닙니다. 예를 들어 C #은 허용 하지만 파이썬은 그렇지 않습니다.
Dmitry Grigoryev

2
@MathiasEttinger 예외를 사용하는 방법과시기에 대한 Python의 지침은 C #과 매우 다르므로 Python 모듈의 동작을 지침으로 사용하는 것은 C #에 대한 좋은 지표가 아닙니다.
Ant P

2
파이썬을 선택하는 대신 SQL을 선택할 수 있습니다. 않습니다 잘 형성된 SELECT 결과 집합이 비어있을 때 테이블에 쿼리 예외를 생산? (스포일러 : 아니오!). 쿼리의 "잘 구성된"은 쿼리 자체와 일부 메타 데이터 에만 의존합니다 (예 : 테이블이 존재하고이 필드가있는이 필드가 있습니까?) 쿼리가 올바르게 구성되고 실행되면 "서버"에 문제가 있기 때문에 (예 : 비 었음) 유효한 결과 또는 예외 (예 : db 서버가 다운되었거나 무언가).
Bakuriu

72

평신도의 관점에서 :

  • 오류가 있으면 예외를 제기해야합니다. 오류가 발생한 위치를 정확히 파악하기 위해 단일 연결 호출 대신 단계적으로 작업을 수행해야 할 수 있습니다.
  • 오류가 없지만 결과 집합이 비어 있으면 예외를 발생시키지 말고 빈 집합을 반환하십시오. 빈 세트는 유효한 세트입니다.

23
+1, 0은 완벽하게 유효하며 실제로 매우 중요한 숫자입니다. 쿼리가 합법적으로 제로 적중을 반환하여 예외를 발생시키는 것이 매우 성가신 경우가 너무 많습니다.
Kilian Foth

19
좋은 조언이지만 대답이 분명합니까?
Ewan

54
이 답변이 OP가 throw빈 세트를 반환 해야하는지 또는 빈 세트를 반환 해야하는지에 대해서는 아직 더 현명하지 않습니다 .
James Snell

7
귀하의 답변에 오류가 있는지 여부에 따라 둘 중 하나를 수행 할 수 있다고 나와 있지만 예제 시나리오를 오류로 간주할지 여부는 언급하지 않았습니다. 위의 의견에서 "문제가없는 경우"빈 세트를 반환해야한다고 말하지만 만족스럽지 못한 조건은 문제로 간주 될 수 있으며 계속해야 할 때 예외를 제기하지 않는다고 말합니다. 그래서 어떻게해야합니까?
anaximander

3
아, 알 겠어요-당신은 오해했을 수도 있습니다; 나는 체인을 연결하지 않고 체인에서 사용될 것으로 예상되는 방법을 작성하고 있습니다. 이 방법을 사용하는 가상의 미래 개발자가 위 시나리오에서 던지기를 원하는지 궁금합니다.
anaximander

53

나는 Ewan의 대답에 동의 하지만 구체적인 추론을 추가하고 싶습니다.

수학적 연산을 다루고 있으므로 동일한 수학적 정의를 고수하는 것이 좋습니다. 수학적 관점에서의 수 R에 의 -sets N 개의 -set (즉 NCR은 )도 모두 R의 정의> N> = 0은 제로이다. 따라서 빈 세트를 반환하는 것은 수학적 관점에서 예상되는 경우입니다.


9
이것은 좋은 지적입니다. 팔레트를 만들기 위해 색상 조합을 선택하는 것과 같이 라이브러리의 수준이 높으면 오류가 발생하는 것이 좋습니다. 이 때문에 알 수 없는 색상 팔레트를 팔레트 아니다. 그러나 항목이없는 세트는 여전히 세트이며 수학은 해당 세트를 빈 세트와 동일하게 정의합니다.
Captain Man

1
Ewans의 답변보다 훨씬 더 나은 수학 연습을 인용합니다. +1
user949300

24

예외 사용 여부를 결정하는 좋은 방법을 찾고 사람들이 거래에 참여하고 있다고 상상하는 것입니다.

파일 내용을 예로 들어 오기 :

  1. "does n't exist.txt"파일 내용을 가져 오십시오.

    에이. "내용은 다음과 같습니다 : 빈 문자 모음"

    비. "음, 문제가 있는데 그 파일이 존재하지 않습니다. 어떻게해야할지 모르겠습니다!"

  2. 파일의 내용을 가져 오십시오. "존재하지만 비어 있습니다 .txt"

    에이. "내용은 다음과 같습니다 : 빈 문자 모음"

    비. "음, 문제가 있습니다.이 파일에는 아무 것도 없습니다. 어떻게해야할지 모르겠습니다!"

의심 할 여지없이 일부 사람들은 동의하지 않을 것이지만 대부분의 사람들에게 파일이 존재하지 않을 때는 "문제가 있습니다"라는 말이 의미가 있고 파일이 비어 있으면 "빈 문자 모음"을 반환합니다.

따라서 동일한 접근법을 예제에 적용하십시오.

  1. 에 대한 4 가지 항목의 모든 조합을 알려주십시오. {1, 2, 3}

    에이. 아무것도 없습니다. 여기에 빈 세트가 있습니다.

    비. 문제가 있습니다. 어떻게해야할지 모르겠습니다.

다시 말해, "문제가있다"는 예를 들어 null아이템 세트로 제공된 경우 에는 의미가 있지만 "여기서 빈 세트"는 위의 요청에 대한 합리적인 응답으로 보입니다.

빈 값을 반환하면 문제 (예 : 누락 된 파일, a null)가 마스킹 되는 경우 일반적으로 예외를 사용해야합니다 (선택한 언어가 option/maybe유형을 지원하지 않는 경우 에는 때때로 더 의미가 있습니다). 그렇지 않으면, 빈 값을 반환하면 비용을 단순화 할 수 있고 놀랍게도 최소화 할 수 있습니다.


4
이 조언은 좋지만이 경우에는 적용되지 않습니다. 더 좋은 예 : 1 월 30 일 이후에 며칠이 지났습니까? : 1 2 월 30 일 이후에 며칠이 지났습니까? : 0 30 일째에 30 일째에 며칠이 지났습니까? : 2 월 중 : 예외
Guran

9

범용 라이브러리이므로 최종 사용자가 선택하도록하십시오.

우리가 가지고 Parse()있고 TryParse()사용할 수있는 것과 마찬가지로 함수에서 필요한 출력에 따라 사용할 수있는 옵션을 가질 수 있습니다. 단일 버전의 함수를 선택하는 것보다 예외를 발생시키기 위해 함수 래퍼를 작성하고 유지 관리하는 데 시간이 덜 걸립니다.


3
+1은 항상 선택한 아이디어를 좋아하기 때문에이 패턴에는 프로그래머가 자신의 입력을 확인하도록 권장하는 경향이 있기 때문입니다. TryFoo 함수의 존재만으로도 특정 입력 조합으로 인해 문제가 발생할 수 있으며 설명서에서 이러한 잠재적 문제가 무엇인지 설명하면 코더가 예외를 포착하여 가능한 것보다 잘못된 방식으로 잘못된 입력을 확인하고 처리 할 수 ​​있습니다. 또는 빈 세트에 응답합니다. 아니면 게으르다. 어느 쪽이든 결정은 그들의 결정입니다.
aleppke

19
아니요, 빈 세트는 수학적으로 정답입니다. 다른 일을하는 것은 확고히 합의 된 수학을 재정의하는 것이며 변덕스럽지 않아야합니다. 우리가 그것에있는 동안 지수가 0과 같으면 에러를 던지도록 지수 함수를 재정의 할 것입니다. 왜냐하면 우리는 "제로"거듭 제곱으로 올린 숫자가 1과 같다는 규칙을 좋아하지 않기 때문입니다.
와일드 카드

1
나는 비슷한 것에 대답하려고했다. Linq의 확장 방법 Single()SingleOrDefault()즉시 마음에 튀어. 결과가 0보다 크거나> 1이면 Single에서 예외가 발생하지만 SingleOrDefault는 발생하지 않고 대신을 반환합니다 default(T). 아마도 OP는 CombinationsOf()및을 사용할 수 있습니다 CombinationsOfOrThrow().
RubberDuck

1
@Wildcard-동일한 입력이 아닌 동일한 두 가지 결과에 대해 이야기하고 있습니다. OP는 a) 결과 또는 b) 결과 가 아닌 예외를 선택하는 데에만 관심 이 있습니다.
James Snell

4
SingleSingleOrDefault(또는 FirstFirstOrDefault) 완전히 다른 이야기, @RubberDuck 있습니다. 이전 의견에서 예를 들었습니다. "두 개보다 큰 소수도 무엇입니까?"라는 쿼리에 아무 것도 신경 쓰지 않는 것이 좋습니다. 수학적으로 건전하고 현명한 답변이기 때문입니다. 어쨌든, "두 번째보다 큰 첫 번째 소수는 무엇입니까?" 자연스러운 대답은 없습니다. 단일 번호를 요청하기 때문에 질문에 대답 할 수 없습니다. 0이 아닌 없음 (단일 숫자가 아니라 세트)이 아니므로 예외가 발생합니다.
Paul Kertscher

4

함수가 호출 될 때 제공된 인수의 유효성을 검증해야합니다. 사실, 잘못된 인수를 처리하는 방법을 알고 싶습니다. 여러 인수가 서로 의존한다는 사실은 인수의 유효성을 검증한다는 사실을 보완하지 않습니다.

따라서 사용자가 무엇이 잘못되었는지 이해하는 데 필요한 정보를 제공하는 ArgumentException에 투표합니다.

예를 들어 public static TSource ElementAt<TSource>(this IEnumerable<TSource>, Int32)Linq 의 기능을 확인하십시오 . 인덱스가 0보다 작거나 소스의 요소 수보다 크거나 같은 경우 ArgumentOutOfRangeException이 발생합니다. 따라서 인덱스는 호출자가 제공 한 열거 가능 항목과 관련하여 검증됩니다.


3
언어에서 비슷한 상황의 예를 들어 +1.
제임스 스넬

13
이상하게도, 당신의 모범은 나를 생각하게 만들었고, 나는 강한 반례를 만드는 것으로 이끌었습니다. 앞서 언급했듯이이 방법은 LINQ와 유사하게 설계되어 사용자가 다른 LINQ 방법과 함께 연결할 수 있습니다. 당신이 경우에 new[] { 1, 2, 3 }.Skip(4).ToList();당신이 날 빈 집합을 반환하는 것은 아마 여기에 더 나은 선택이라고 생각하게 빈 세트를 얻을.
anaximander

14
이것은 언어 의미론 문제가 아니며 문제 도메인의 의미론은 이미 정답을 제공합니다. 즉, 빈 세트를 반환합니다. 다른 일을하는 것은 조합 문제 영역에서 일하는 사람에게는 최소한의 놀랍게도의 원칙을 위반합니다.
Ukko

1
빈 세트를 반환하는 인수를 이해하기 시작했습니다. 왜 말이 되겠 어? 적어도이 특정 예에서는.
sbecker

2
@ sbecker, 요점을 집으로 가져 오기 : 질문이 "얼마나 많은 조합이 있는지 ..."라면 "제로"는 완전히 유효한 답이 될 것입니다. 같은 토큰으로, " ...와 같은 조합 무엇입니까 ?"는 완전히 유효한 답으로 빈 세트를 갖습니다. " 첫 번째 조합 은 무엇입니까?"라는 질문이 있다면 , 그 질문에 대답 할 수 없기 때문에 예외가 적절할 것입니다. Paul K의 의견 도 참조하십시오 .
와일드 카드

3

다음 중 하나를 수행해야합니다 (음수 조합과 같은 기본 문제가 계속 발생 함).

  1. 두 가지 구현을 제공하십시오. 하나는 입력이 함께 의미가 없을 때 빈 세트를 리턴하고 다른 하나는 던집니다. 그들을 호출 시도 CombinationsOf하고 CombinationsOfWithInputCheck. 또는 원하는대로. 입력을 확인하는 이름이 더 짧은 이름이고 목록이 이름이되도록 이것을 반대로 바꿀 수 있습니다 CombinationsOfAllowInconsistentParameters.

  2. Linq 메소드의 경우, IEnumerable당신이 설명한 정확한 전제 에서 공란 을 반환하십시오 . 그런 다음 Linq 메소드를 라이브러리에 추가하십시오.

    public static class EnumerableExtensions {
       public static IEnumerable<T> ThrowIfEmpty<T>(this IEnumerable<T> input) {
          return input.IfEmpty<T>(() => {
             throw new InvalidOperationException("An enumerable was unexpectedly empty");
          });
       }
    
       public static IEnumerable<T> IfEmpty<T>(
          this IEnumerable<T> input,
          Action callbackIfEmpty
       ) {
          var enumerator = input.GetEnumerator();
          if (!enumerator.MoveNext()) {
             // Safe because if this throws, we'll never run the return statement below
             callbackIfEmpty();
          }
          return EnumeratePrimedEnumerator(enumerator);
       }
    
       private static IEnumerable<T> EnumeratePrimedEnumerator<T>(
          IEnumerator<T> primedEnumerator
       ) {
          yield return primedEnumerator.Current;
          while (primedEnumerator.MoveNext()) {
             yield return primedEnumerator.Current;
          }
       }
    }

    마지막으로 다음과 같이 사용하십시오.

    var result = someInputSet
       .CombinationsOf(4, CombinationsGenerationMode.Distinct)
       .ThrowIfEmpty()
       .Select(combo => /* do some operation to a combination */)
       .ToList();

    또는 이와 같이 :

    var result = someInputSet
       .CombinationsOf(4, CombinationsGenerationMode.Distinct)
       .IfEmpty(() => _log.Warning(
          $@"Unexpectedly received no results when creating combinations for {
             nameof(someInputSet)}"
       ))
       .Select(combo => /* do some operation to a combination */)
       .ToList();

    linq 체인이 나중에 열거 될 때가 아니라 생성 될 때 던지기 또는 동작 동작이 발생하도록하려면 공개 메소드와 다른 개인 메소드가 필요합니다. 당신 그것이 바로 던져지기를 원합니다 .

    그러나 물론 항목이 있는지 확인하려면 적어도 첫 번째 항목을 열거해야합니다. 이것은 미래의 모든 시청자가 ThrowIfEmpty메서드 적어도 하나의 항목을 열거 해야한다는 것을 쉽게 추론 할 수 있다는 사실에 의해 잠재적으로 단점이 있다고 생각 합니다 . 그래서 그렇게 놀라지 않아야 합니다. 그러나 당신은 모른다. 이를보다 명확하게 만들 수 ThrowIfEmptyByEnumeratingAndReEmittingFirstItem있습니다. 그러나 그것은 엄청난 과잉처럼 보입니다.

# 2는 꽤 훌륭합니다. 이제 힘은 호출 코드에 있으며 다음 코드 리더는 코드가 수행하는 작업을 정확히 이해하므로 예기치 않은 예외를 처리 할 필요가 없습니다.


무슨 뜻인지 설명해주세요. 내 게시물의 내용이 어떻게 "집합처럼 행동하지 않습니까"그리고 왜 나쁜 것입니까?
ErikE

당신은 기본적으로 내 대답과 동일합니다. If 조건을 쿼리하기 위해 발생한 쿼리를 래핑하는 대신 결과가 변경되지 않습니다.
GameDeveloper

내 답변이 귀하의 답변과 "기본적으로 동일한 방식으로"수행되는 것을 볼 수 없습니다. 그들은 나에게 완전히 다른 것처럼 보입니다.
ErikE

기본적으로 당신은 "나의 나쁜 클래스"와 같은 조건을 시행하고 있습니다. 그러나 당신은 ^^. 쿼리 결과에 1 개의 요소가 존재한다는 데 동의하십니까?
게임 개발자

아직도 당신이 말하는 것을 얻지 못하는 어리석은 프로그래머를 위해 더 명확하게 말해야 할 것입니다. 어떤 수업이 나쁜가요? 왜 나쁜가요? 나는 아무것도 시행하지 않습니다. 클래스의 사용자가 클래스의 CREATOR 대신 최종 동작을 결정할 수 있습니다. 이를 통해 Linq 메소드가 한 번에 -1 개의 항목을 요청한 경우와 같은 일반적인 규칙을 위반하지 않는 계산적 측면으로 인해 무작위로 던지지 않는 일관된 코딩 패러다임을 사용할 수 있습니다.
ErikE

2

두 유스 케이스 모두에 대한 인수를 볼 수 있습니다. 다운 스트림 코드가 데이터를 포함하는 세트를 기대하는 경우 예외가 좋습니다. 반면, 이것이 예상된다면 단순히 빈 세트가 좋습니다.

나는 이것이 오류이거나 수용 가능한 결과 인 경우 발신자의 기대에 달려 있다고 생각하므로 선택을 발신자에게 이전합니다. 옵션을 소개 하시겠습니까?

.CombinationsOf(4, CombinationsGenerationMode.Distinct, Options.AllowEmptySets)


10
나는 당신이 어디로 가고 있는지 알지만, 그들의 행동을 수정하는 많은 옵션이 전달 된 메소드를 피하려고합니다. 나는 이미 존재하는 모드 열거에 100 % 만족하지 않습니다. 메서드의 예외 동작을 변경하는 옵션 매개 변수가 마음에 들지 않습니다. 메소드가 예외를 던질 필요가 있다면, 던질 필요가 있다고 생각합니다. 호출 코드로 결정한 예외를 숨기려면 올바른 입력 옵션을 사용하여 내 코드에서 할 수있는 것이 아닙니다.
anaximander

호출자가 비어 있지 않은 세트를 예상하면, 빈 세트를 처리하거나 예외를 던지는 것은 호출자에게 달려 있습니다. 수신자에 관한 한, 빈 세트는 완벽하게 훌륭한 답변입니다. 그리고 빈 세트가 좋은지 아닌지에 대해 다른 의견을 가진 한 명 이상의 발신자를 가질 수 있습니다.
gnasher729

2

명확한 답이 없는지 결정하는 두 가지 방법이 있습니다.

  • 첫 번째 옵션을 가정하고 다른 옵션을 가정하여 코드를 작성하십시오. 실제로 가장 효과적인 방법을 고려하십시오.

  • "엄격한"부울 매개 변수를 추가하여 매개 변수를 엄격하게 검증할지 여부를 표시하십시오. 예를 들어, Java 에는 형식과 완전히 일치하지 않는 입력 구문 분석을 시도 SimpleDateFormat하는 setLenient메소드가 있습니다. 물론, 기본값이 무엇인지 결정해야합니다.


2

자체 분석을 기반으로 빈 세트를 반환하는 것이 옳은 것처럼 보입니다. 사용자가 실제로 사용하기를 원하고 사용자가 사용하기를 원하지 않기 때문에 일부 사용을 금지하는 함정에 빠지지 않은 것으로 식별했습니다. 그런 식으로.

일부 사용자가 비어 있지 않은 반품을 강요하고 싶을 경우, 모든 사용자에게 해당 행동을 강요하는 대신 그 행동 을 요구할 수있는 방법을 제공하십시오 . 예를 들어 다음을 수행 할 수 있습니다.

  • 사용자에 대한 조치를 수행하는 모든 오브젝트에서 구성 옵션으로 만드십시오.
  • 사용자가 선택적으로 함수에 전달할 수있는 플래그로 지정하십시오.
  • AssertNonempty그들이 체인에 넣을 수 있는 수표를 제공하십시오 .
  • 비어 있지 않은 것과 그렇지 않은 것을 두 가지 함수로 만듭니다.

이것은 이전 12 답변에서 만들어지고 설명 된 점을 넘어서는 실질적인 것을 제공하지 않는 것 같습니다
gnat

1

그것은 실제로 사용자가 기대하는 것에 달려 있습니다. 코드가 나누기를 수행하는 경우 (약간 관련이없는) 예제의 경우 예외를 던지거나 반환 Inf하거나 NaN0으로 나눌 때. 그러나 옳고 그른 것도 아닙니다 :

  • Inf파이썬 라이브러리로 돌아 오면 사람들이 오류를 숨기고 공격합니다.
  • Matlab 라이브러리에서 오류가 발생하면 누락 된 값을 가진 데이터를 처리하지 못한 사람들이 사용자를 공격합니다.

귀하의 경우 최종 사용자에게는 가장 놀라운 솔루션을 선택합니다. 세트를 다루는 라이브러리를 개발하고 있기 때문에 빈 세트는 사용자가 처리 할 것으로 예상되는 것처럼 보이므로 반환하는 것이 현명한 일처럼 들립니다. 그러나 나는 틀릴 수 있습니다 : 당신은 여기의 다른 사람보다 컨텍스트를 훨씬 잘 이해하고 있습니다. 따라서 사용자가 세트에 항상 의존하지 않기를 기대한다면 예외를 즉시 던져야합니다.

"엄격한"매개 변수 추가와 같이 사용자가 선택할 수있는 솔루션 은 원래 질문을 새로운 동등한 질문으로 대체하기 때문에 결정적이지 않습니다. "어떤 값이 strict기본값이어야합니까?"


2
내 대답에 NaN 인수를 사용하는 것에 대해 생각하고 의견을 공유합니다. OP의 영역을 모르면 더 이상 말할 수 없습니다
GameDeveloper

0

세트에서 요소를 선택할 때 요소를 찾을 수 없으므로 빈 세트를 얻는 것이 일반적인 개념입니다 (수학에서) . 물론 이런 식으로 가면 수학과 일관성이 있어야합니다.

공통 세트 규칙 :

  • Set.Foreach (predicate); // 빈 세트의 경우 항상 true를 반환합니다.
  • Set.Exist (predicate); // 빈 세트의 경우 항상 false를 반환합니다.

귀하의 질문은 매우 미묘합니다.

  • 이 함수의 입력이 가지고있을 수 존중하는 계약 : 함수는 일반 매개 변수 아래 작동하지 않는 경우, 그거야, 유효하지 않은 입력이 예외를 발생해야하는 경우입니다.

  • 함수 입력이 정확히 set과 동일 하게 작동 해야하므로 빈 세트를 반환 할 수 있어야합니다.

내가 당신 안에 있다면 "Set"방식으로 갈 것입니다. 그러나 큰 "BUT"이 있습니다.

"가설에 의해"여학생 만 있어야하는 컬렉션이 있다고 가정 해 봅시다.

class FemaleClass{

    FemaleStudent GetAnyFemale(){
        var femaleSet= mySet.Select( x=> x.IsFemale());
        if(femaleSet.IsEmpty())
            throw new Exception("No female students");
        else
            return femaleSet.Any();
    }
}

이제 계약서가 있기 때문에 귀하의 컬렉션은 더 이상 "순수한 세트"가 아니므로 예외로 계약을 시행해야합니다.

"set"함수를 순수한 방식으로 사용하는 경우 빈 세트의 경우 예외를 발생시키지 말고 더 이상 "순수한 세트"가 아닌 컬렉션이있는 경우 적절한 곳에 예외를 발생 시켜야합니다 .

당신은 항상 더 자연스럽고 일관된 느낌을 유지해야합니다. 나에게는 세트가 정해진 규칙을 준수해야하지만 세트가 아닌 것은 적절하게 생각 된 규칙을 가져야합니다.

귀하의 경우에는 다음을 수행하는 것이 좋습니다.

List SomeMethod( Set someInputSet){
    var result = someInputSet
        .CombinationsOf(4, CombinationsGenerationMode.Distinct)
        .Select(combo => /* do some operation to a combination */)
        .ToList();

    // the only information here is that set is empty => there are no combinations

    // BEWARE! if 0 here it may be invalid input, but also a empty set
    if(result.Count == 0)  //Add: "&&someInputSet.NotEmpty()"

    // we go a step further, our API require combinations, so
    // this method cannot satisfy the API request, then we throw.
         throw new Exception("you requsted impossible combinations");

    return result;
}

그러나, 우리는 약간의 내부를 제외하고 이동할 수 있는지 우리가 우리가 그것을 제거 할 수없는 문제에 암시 적이다 그러나 임의의 순간에서 런타임에 occurr 수 있습니다 지금은 유효하지 않은 상태를 가지고, 정말 좋은 생각이 아니다 유틸리티 메소드를 (정확히입니다 동일한 코드, 다른 장소로 이동), 그러나 틀렸고 기본적으로 할 수있는 가장 좋은 방법은 규칙적인 규칙을 따르는 것 입니다.

실제로 linq 쿼리 메소드를 작성할 수 있음을 보여주기 위해 새로운 복잡성을 추가하면 문제에 가치가없는 것 같습니다 .OP 가 도메인에 대해 더 많이 알려줄 수 있다면 예외가 실제로 필요한 지점을 찾을 수있을 것입니다. 전혀 문제가 전혀 예외를 요구하지 않을 수도 있습니다).


문제는 수학적으로 정의 된 객체를 사용하여 문제를 해결하지만 문제 자체는 수학적으로 정의 된 객체를 답변으로 요구하지 않을 수 있다는 것입니다 (실제로 목록을 반환 함). 문제 해결 방법에 관계없이 문제의 상위 수준에 따라 달라집니다.이를 캡슐화 / 정보 숨기기라고합니다.
GameDeveloper

"SomeMethod"가 더 이상 세트처럼 동작하지 않는 이유는 "Set of Set"에 대한 정보를 요청하고, 주석 처리 된 부분 "&& someInputSet.NotEmpty ()"를 살펴 보는 것입니다.
GameDeveloper

1
아니! 당신은 당신의 여성 클래스에서 예외를 던져서는 안됩니다. FemaleClass암컷 만 (공개적으로 생성 가능하지 않고, 빌더 클래스 만 인스턴스를 전달할 수 있음) 인스턴스가 하나도없는 경우를 제외 하고 인스턴스의 인스턴스를 GET 할 수 없도록하는 빌더 패턴을 사용해야 합니다. . 그런 다음 FemaleClass인수로 사용되는 모든 곳의 코드 는 객체가 잘못된 상태이기 때문에 예외를 처리 할 필요가 없습니다.
ErikE

클래스가 너무 단순하여 실제로 생성자에 의해 전제 조건을 시행 할 수 있다고 가정합니다. 당신은 논쟁에 결함이 있습니다. 더 이상 여성이없는 것을 금지하거나 수업에서 스터드를 제거하는 방법이 없거나 학생이 1 명 남았을 때 예외가 발생해야합니다. 내 문제를 다른 곳으로 옮겼습니다. 요점은 항상 "설계에 의해"유지 될 수없는 전제 조건 / 기능 상태가 있으며 사용자가 중단 할 것이라는 점입니다. 예외가 존재하는 이유! 이것은 꽤 이론적 인 것입니다. 나는 downvote가 당신이 아니기를 바랍니다.
GameDeveloper

downvote는 내 것이 아니지만 그것이 있다면 자랑스럽게 생각 합니다. 신중하게 공감하지만 유죄 판결을 받았습니다. 클래스의 규칙에 항목이 있어야하며 모든 항목이 특정 조건을 충족해야한다면 클래스가 일관성이없는 상태가되도록하는 것은 좋지 않습니다. 다른 곳으로 문제를 옮기는 것이 나의 의도입니다! 내가 원하는 문제를 사용하지 않을시, 시간을 구축 발생할 수 있습니다. 생성자 던지기 대신 Builder 클래스를 사용하는 요점은 불일치를 통해 많은 부분과 부분으로 매우 복잡한 상태를 만들 수 있다는 것입니다.
ErikE
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.