入力が技術的に有効であるが、満足できない場合の例外と空の結果セット


108

私は公開リリースを目的としたライブラリを開発しています。オブジェクトのセットを操作するためのさまざまなメソッドが含まれています-セットを生成、検査、パーティション分割、新しいフォームに投影します。関連する場合IEnumerableは、NuGetパッケージとしてリリースされるLINQスタイルの拡張を含むC#クラスライブラリです。

このライブラリの一部のメソッドには、満たされない入力パラメーターを指定できます。たとえば、組み合わせメソッドには、m個のアイテムのソースセットから構築できるn個のアイテムのすべてのセットを生成するメソッドがあります。たとえば、次のセットを考えます:

1、2、3、4、5

2の組み合わせを要求すると、次の結果が得られます。

1、2
1、3
1、4
等...
5、3
5、4

現在、3つのアイテムのセットを提供し、各アイテムを1回しか使用できないというオプションを設定しながら、4つのアイテムの組み合わせを要求するなど、実行できないことを要求することは明らかに可能です。

このシナリオでは、各パラメーターは個別に有効です。

  • ソースコレクションはnullではなく、アイテムが含まれています
  • 要求された組み合わせのサイズは、ゼロ以外の正の整数です
  • 要求されたモード(各アイテムを1回のみ使用)は有効な選択です

ただし、パラメーターの状態を一緒にすると問題が発生します。

このシナリオでは、メソッドが例外をスローすることを期待しますか(例:)InvalidOperationException、または空のコレクションを返しますか?どちらも私にとって有効なようです:

  • あなたは、の組み合わせを生成することができないn個のセットから項目をm個の項目N> M君はそれゆえ、一度だけ、各アイテムの使用を許可しているので、この操作は不可能と考えることができる場合InvalidOperationException
  • n> mが空のセットである場合にm個のアイテムから生成できるサイズnの組み合わせのセット。組み合わせは作成できません。

空のセットの引数

私の最初の懸念は、サイズが不明なデータセットを処理する場合、例外が慣用的なLINQスタイルのメソッドのチェーンを妨げることです。言い換えれば、あなたはこのようなことをしたいと思うかもしれません:

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

入力セットのサイズが可変の場合、このコードの動作は予測できません。場合は.CombinationsOf()、例外をスローしたときsomeInputSetよりも少ない4つの要素を持っている場合、このコードがします時々、いくつかの事前チェックせずに、実行時に失敗します。上記の例では、このチェックは簡単ですが、より長いLINQチェーンの途中で呼び出す場合、これは面倒になります。それが空のセットを返す場合、空になりますresult

例外の引数

私の2番目の懸念は、空のセットを返すと問題が隠れる可能性があることです-LINQのチェーンの途中でこのメソッドを呼び出して静かに空のセットを返す場合、後でいくつかの手順で問題が発生するか、空の結果セット。入力セットに何かが確実に含まれていた場合、それがどのように発生したかは明らかではないかもしれません。

あなたは何を期待しますか、それに対するあなたの議論は何ですか?


66
空のセットは数学的に正しいため、取得するときに実際に必要なものになる可能性があります。数学的な定義と規則は、一般に一貫性と利便性のために選択されるため、物事がうまく機能します。
asmeurer

5
@asmeurer 定理が一貫して便利になるように選択されています。プログラミングを簡単にするために選ばれたわけではありません。(それは時々副次的な利点ですが、時にはプログラミングも難しくなります。)
jpmc26

7
@ jpmc26「定理が一貫して便利になるように選択されています」-プログラムが常に期待どおりに動作することを確認することは、定理を証明することと本質的に同等です。
アルテム

2
@ jpmc26関数型プログラミングに言及した理由がわかりません。命令型プログラムの正しさを証明することは非常に可能であり、常に有利であり、非公式に行うこともできます。1つのサンプルで統計的に証明されています;
artem

5
未定義の@DmitryGrigoryev 1/0は、無限の1/0よりも数学的に正確です。
asmeurer

回答:


145

空のセットを返す

私は空のセットを期待しています:

各番号を1回しか使用できない場合、3つのセットから4つの番号の0個の組み合わせ


5
数学的には、はい、しかしそれはまた、エラーの原因である可能性が非常に高いです。このタイプの入力が予想される場合、ユーザーが汎用ライブラリーで例外をキャッチすることを要求する方がよい場合があります。
ケーシークーボール

56
これがエラーの「非常に可能性の高い」原因であることに同意しません。たとえば、大きな入力セットから単純な「matchmaknig」アルゴリズムを実装しているとします。2つのアイテムのすべての組み合わせを要求し、それらの間で単一の「最適な」一致を見つけてから、両方の要素を削除して、新しい小さいセットからやり直すことができます。最終的にセットは空になり、考慮すべきペアは残りません。この時点での例外は邪魔です。同様の状況に陥るには多くの方法があると思います。
アマロイ

11
実際に、これがユーザーの目に誤りであるかどうかはわかりません。空のセットは、必要に応じてユーザーが確認する必要があるものです。if(result.Any())DoSomething(result.First()); それ以外の場合DoSomethingElse(); 試みるよりもはるかに優れている。キャッチ{DoSomethingElse();} {result.first())(doSomethingの}
Guran

4
@TripeHound最終的に決定を下したのは、この方法を使用して開発者がチェックしてからスローすることを要求することは、開発努力、プログラムのパフォーマンス、およびプログラムフローのシンプルさ。
アナキシマンダー16

6
@Darthfettこれを既存のLINQ拡張メソッドWhere()と比較してみてください。句がある場合:Where(x => 1 == 2)例外は発生せず、空のセットが取得されます。
ネコラス16

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の回答を参照してください)。これがPythonの質問であれば、私からの+1になります。
ジェームズスネル

32
@JamesSnell私はそれが範囲外の問題にどのように関係しているかほとんどわかりません。インデックスで要素を選択して並べ替えるのではなくn、コレクション内の要素を選択して、それらを選択できる方法の数を数えます。ある時点で要素を選択するときに要素が残っていない場合、そのnコレクションから要素を選択する方法はありません。
マティアスエッティンガー

1
それでも、PythonはC#の質問に適したオラクルで1.0 / 0はありません。たとえば、C#は許可しますが、Pythonは許可しません。
ドミトリーグリゴリエフ

2
@MathiasEttinger例外を使用する方法とタイミングに関するPythonのガイドラインはC#のガイドラインとは非常に異なるため、Pythonモジュールの動作をガイドラインとして使用することはC#の適切なメトリックではありません。
Ant P

2
Pythonを選ぶ代わりに、SQLを選ぶことができます。よく形成され SELECT、結果セットが空の場合、テーブルの上にクエリは例外を作りますか?(ネタバレ:いいえ!)。クエリの「整形式」は、クエリ自体と一部のメタデータのみに依存します(たとえば、テーブルが存在し、(このタイプの)このフィールドがありますか?)クエリが整形式で実行すると、 (おそらく空)有効な結果または「サーバー」に問題があったための例外(たとえば、dbサーバーがダウンしたなど)。
バクリウ16

72

素人の言葉で:

  • エラーがある場合は、例外を発生させる必要があります。エラーが発生した場所を正確に知るために、単一のチェーンコールではなく、ステップで物事を行う必要があります。
  • エラーはないが、結果のセットが空の場合、例外を発生させず、空のセットを返します。空のセットは有効なセットです。

23
+1、0は完全に有効であり、実際に非常に重要な数値です。クエリが正当にゼロヒットを返す場合が非常に多いので、例外の発生は非常に迷惑です。
キリアンフォス

19
良いアドバイスですが、あなたの答えは明確ですか?
ユアン

54
私はまだこの答えはOPがすべき示唆している場合にのように賢く何もしていないthrow...または空のセットを返す
ジェームズスネル

7
あなたの答えは、エラーがあるかどうかに応じてどちらでもできると言っていますが、シナリオの例をエラーとみなすかどうかについては言及していません。上記のコメントでは、「問題がなければ」空のセットを返す必要がありますが、ここでも、満足できない条件は問題と見なされる可能性があります。それで、私はどちらをすべきですか?
アナキシマンダー

3
ああ、わかりました-あなたは誤解しているかもしれません。私は何も連鎖していません。連鎖で使用されることを期待するメソッドを書いています。このメソッドを使用する架空の将来の開発者が、上記のシナリオでこのメソッドをスローすることを望んでいるかどうか疑問に思っています。
アナキシマンダー

53

ユアンの答えには同意しますが、具体的な理由を付け加えたいと思います。

あなたは数学的操作を扱っているので、同じ数学的定義に従うことは良いアドバイスかもしれません。数学的な観点から、nセットのrセット(つまりnCr)の数は、すべてのr> n> = 0に対して明確に定義されています。これはゼロです。したがって、数学的な観点からは、空のセットを返すことが期待されます。


9
これは良い点です。色の組み合わせを選択してパレットを作成するなど、ライブラリのレベルが高い場合は、エラーをスローするのが理にかなっています。あなたがいるので知っていない色でパレットをパレットではありません。ただし、エントリのないセットはまだセットであり、数学では空のセットと等しいと定義されています。
キャプテンマン

1
ユアンスの答えよりもはるかに優れているのは、数学の実践を引用しているからです。+1
user949300 16

24

例外を使用するかどうかを判断する良い方法は、トランザクションに関係する人々を想像することです。

例としてファイルの内容を取得することを考えます:

  1. 「does n't exist.txt」というファイルの内容を取得してください

    a。「内容は次のとおりです。文字の空のコレクション」

    b。「問題があります。そのファイルは存在しません。何をすべきかわかりません!」

  2. 「存在するがempty.txt」というファイルの内容を取得してください

    a。「内容は次のとおりです。文字の空のコレクション」

    b。「ええ、問題があります。このファイルには何もありません。何をすべきかわかりません!」

疑いの余地はありませんが、ほとんどの人にとって、「問題があります」というのは、ファイルが存在しない場合に意味があり、ファイルが空の場合は「文字の空のコレクション」を返します。

したがって、同じアプローチを例に適用します。

  1. 4つのアイテムのすべての組み合わせを教えてください {1, 2, 3}

    a。何もありません、空のセットです。

    b。問題があります、私は何をすべきかわかりません。

繰り返しますが、「問題があります」は、たとえばnullアイテムのセットとして提供された場合に意味がありますが、「ここに空のセットがあります」は上記の要求に対する賢明な応答のようです。

空の値を返すことが問題を隠している場合(たとえば、ファイルの欠落、a null)、通常は代わりに例外を使用する必要があります(選択した言語がoption/maybe型をサポートしている場合を除き、より意味があります)。それ以外の場合、空の値を返すとコストが単純化される可能性が高く、最小限の驚きの原則により適合します。


4
このアドバイスは適切ですが、この場合には適用されません。より良い例:1月30日から何日後?:1 2月30日から何日後?:0メイクアップ後30日から何日後か:例外30の労働時間:2
グラン

9

汎用ライブラリーであるため、私の本能はエンドユーザーに選択させることです。

私たちが持っているのParse()と同じようにTryParse()、関数から必要な出力に応じて使用するオプションを持つことができます。関数の単一のバージョンを選択することについて議論するよりも、例外をスローするために関数ラッパーを作成および保守する時間を短縮できます。


3
なぜなら、私は常に選択のアイデアが好きであり、このパターンはプログラマーが自分の入力を検証することを奨励する傾向があるためです。TryFoo関数の単なる存在は、特定の入力の組み合わせが問題を引き起こす可能性があることを明らかにし、ドキュメントがそれらの潜在的な問題が何であるかを説明している場合、コーダーはそれらをチェックし、単に例外をキャッチするよりもきれいな方法で無効な入力を処理できますまたは空のセットに応答します。または、彼らは怠zyになることができます。いずれにせよ、決定は彼らのものです。
-aleppke

19
いいえ、空のセットは数学的に正しい答えです。他の何かをすることは、しっかりと合意された数学を再定義することであり、気まぐれに行われるべきではない。そのとき、指数がゼロに等しい場合、指数関数を再定義してエラーをスローする必要があります。これは、「ゼロ」乗した数値が1に等しいという規則が気に入らないためです。
ワイルドカード

1
私は似たようなことに答えようとしていました。LINQの拡張メソッドSingle()SingleOrDefault()、すぐに頭に生まれて。Singleは、結果が0または> 1の場合に例外をスローしますが、SingleOrDefaultはスローせず、代わりにを返しますdefault(T)。おそらくOPはCombinationsOf()andを使用できますCombinationsOfOrThrow()
ラバーダック16

1
@Wildcard-同じ入力に対する2つの異なる結果について話していますが、これは同じものではありません。OPは、a)結果を選択するか、b)結果ではない例外をスローすることにのみ関心があります。
ジェームズ・スネル

4
Singleand SingleOrDefault(or Firstand FirstOrDefault)はまったく異なる話、@ RubberDuckです。以前のコメントから例を取り上げます。「3つ以上の素数が存在しますか?」という質問に答えることはまったく問題ありません。、これは数学的に健全で賢明な答えだからです。とにかく、「最初の2以上の素数は何ですか?」自然な答えはありません。質問に答えることはできません。単一の番号を要求しているからです。そうではありませんんどれも私たちは例外をスローしたがって、(それは、単一の番号ではないが、セット)、0でありません。
ポールケルシャー16

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();、あなたは私が空のセットを返すことは、おそらくここに、より良い選択肢であることを思わせる空のセットを、取得します。
アナキシマンダー

14
これは言語のセマンティクスの問題ではありません。問題のドメインのセマンティクスはすでに正しい答えを提供しています。つまり、空のセットを返します。他のことをすることは、組み合わせ問題の領域で働いている誰かにとって、最も驚かないという原則に違反します。
-Ukko

1
空のセットを返すための引数を理解し始めています。なぜそれが理にかなっているのか。少なくともこの特定の例では。
sbecker 16

2
質問は「どのようにした場合は、次の点を持ち帰るために@sbecker、多くのある組み合わせ...」そして「ゼロ」は完全に有効な回答になります。同様に、「...のような組み合わせ何ですか」には、完全に有効な答えとして空のセットがあります。質問が「...のような最初の組み合わせは何ですか」である場合、その質問は答えられないため、例外が適切になります。Paul Kのコメントも参照してください。
ワイルドカード

3

次のいずれかを実行する必要があります(ただし、負の数の組み合わせなどの基本的な問題を継続的にスローします)。

  1. 入力が無意味な場合に空のセットを返す実装と、スローする実装の2つの実装を提供します。それら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チェーンが列挙されるときではなく、linqチェーンが作成されるときにスローまたはアクション動作が発生するためには、パブリックメソッドとは異なるプライベートメソッドが必要であることに注意してください。あなたは欲しい、それはすぐにスローします。

    ただし、当然ながら、アイテムがあるかどうかを判断するには、少なくとも最初のアイテムを列挙する必要があります。これは潜在的な欠点であり、将来の視聴者はThrowIfEmptyメソッド少なくとも1つの項目を列挙する必要があると非常に簡単に推論できるため、驚くことはないはずです。しかし、あなたは決して知りません。これをより明確にすることができThrowIfEmptyByEnumeratingAndReEmittingFirstItemます。しかし、それは巨大な行き過ぎのようです。

#2は非常に素晴らしいと思います!これで、呼び出し元のコードに力が加わり、コードの次のリーダーはそれが何をしているかを正確に理解し、予期しない例外に対処する必要がなくなります。


意味を説明してください。私の投稿の「セットのように振る舞わない」とはどういうことですか、なぜそれが悪いのですか?
エリック16

あなたは基本的に私の答えと同じことをしています
。If

私の答えがあなたの答えの「基本的に同じ」であることがわかりません。私にはまったく違うようです。
エリック16

基本的に、あなたは「私の悪いクラス」と同じ条件を強制しているだけです。しかし、あなたはそれを言っていません^^。クエリ結果に1つの要素が存在することを強制していることに同意しますか?
GameDeveloper 16

あなたが話していることをまだ理解していない明らかに愚かなプログラマーのために、あなたはもっとはっきりと話さなければならないでしょう。どのクラスが悪いですか?どうして悪いの?私は何も強制していません。クラスのUSERがクラスのCREATORの代わりに最終的な動作を決定できるようにします。これにより、一度に-1アイテムを要求した場合など、通常のルールに実際には違反していない計算面のために、Linqメソッドがランダムにスローしない一貫したコーディングパラダイムを使用できます。
エリック16

2

両方のユースケースの引数を見ることができます-ダウンストリームのコードがデータを含むセットを期待している場合、例外は素晴らしいです。一方、もしこれが期待されるなら、単に空のセットは素晴らしいです。

これがエラーであるか、許容できる結果であるかどうかは、発信者の期待にかかっていると思うので、選択を発信者に転送します。おそらくオプションを導入しますか?

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


10
私はあなたがこれでどこに行くのかを得ていますが、私はそれらの振る舞いを変更する多くのオプションが渡されるメソッドを避けるようにします。既にあるモード列挙型にはまだ100%満足していません。メソッドの例外動作を変更するオプションパラメーターのアイデアは、本当に好きではありません。メソッドが例外をスローする必要がある場合、スローする必要があるように感じます。その例外を非表示にしたい場合は、呼び出しコードとしての決定であり、適切な入力オプションを使用してコードを実行することはできません。
アナキシマンダー

呼び出し元が空でないセットを予期している場合、空のセットを処理するか例外をスローするのは呼び出し元の責任です。呼び出し先に関する限り、空のセットは完全に良い答えです。また、空のセットが適切かどうかについて異なる意見を持つ複数の呼び出し元を持つことができます。
gnasher729 16

2

明らかな答えがないかどうかを判断するには、2つのアプローチがあります。

  • 最初に1つのオプション、次に他のオプションを想定してコードを記述します。どちらが実際に最もよく機能するかを検討してください。

  • 「厳密な」ブール値パラメーターを追加して、パラメーターを厳密に検証するかどうかを示します。たとえば、JavaにSimpleDateFormatsetLenient、形式と完全に一致しない入力の解析を試みるメソッドがあります。もちろん、デフォルトが何であるかを決める必要があります。


2

独自の分析に基づいて、空のセットを返すことは明らかに正しいようです。ユーザーが実際に望んでいるものであると特定し、ユーザーがそれを使用することを想像できないため、使用を禁止するというintoに陥っていませんそのように。

一部のユーザーが空でない返品を強制したい場合は、全員に強制するのではなく、その動作を要求する方法を提供してください。たとえば、次のことができます。

  • ユーザーのアクションを実行しているオブジェクトの構成オプションにします。
  • ユーザーがオプションで関数に渡すことができるフラグにします。
  • AssertNonemptyチェーンに入れることができるチェックを提供します。
  • 2つの関数を作成します。1つは空でないことをアサートし、もう1つはそうではありません。

ポイントが作られ、前12件の答えで説明した上で、これはかなりのものを提供していないようだ
ブヨ

1

それは、ユーザーが何を期待しているのかに本当に依存しています。(やや無関係な)コードで除算を実行する場合、例外を返すInfNaN、リターンするか、ゼロで除算する場合があります。ただし、どちらも正しいことも間違っていることもありません。

  • InfPythonライブラリに戻ると、人々はエラーを隠すためにあなたを攻撃します
  • Matlabライブラリでエラーが発生すると、欠損値のあるデータの処理に失敗したために人々があなたを攻撃します

あなたの場合、私はエンドユーザーにとって最も驚くべきソリューションを選びます。セットを扱うライブラリを開発しているので、空のセットはユーザーが扱うことを期待しているように見えるので、それを返すことは賢明なことのように聞こえます。しかし、私は間違っているかもしれません:あなたはここで他の誰よりもコンテキストをはるかによく理解しているので、ユーザーが常に空ではないセットに依存することを期待する場合は、すぐに例外をスローする必要があります。

ユーザーが選択できるソリューション(「厳格な」パラメーターの追加など)は、元の質問を新しい同等の質問「どの値をstrictデフォルトにするか」に置き換えるため、決定的なものではありません。


2
私は答えにNaN引数を使用することを考えました、そしてあなたの意見を共有します。私たちは、OPのドメインを知らなくても、多くを伝えることができない
GameDeveloper

0

セット上で要素を選択すると、要素が見つからないため、空のセットを取得することが一般的な概念です(数学)。もちろん、この方法を使用する場合は、数学と一貫している必要があります。

一般的なセットルール:

  • Set.Foreach(述語); //空のセットに対して常にtrueを返します
  • Set.Exists(述語); //空のセットに対しては常にfalseを返します

あなたの質問は非常に微妙です:

  • それはあなたの関数の入力が持っている可能性が尊重する契約をその場合は、無効な入力機能は、通常のパラメータの下で動作していない、それはそれだ、例外を発生させなければなりません。

  • 関数の入力はsetまったく同じように動作する必要があるため、空のsetを返すことができるはずです。

今、私があなたの中にいたら、私は「セット」の方法に行きますが、大きな「しかし」で。

「仮説による」女子学生のみが含まれるコレクションがあるとします。

class FemaleClass{

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

これで、あなたのコレクションは「純粋なセット」ではなくなりました。なぜならあなたはその上で契約を結んでいるからです。したがって、例外を除いて契約を実施すべきです。

「セット」関数を純粋な方法で使用する場合、空のセットの場合に例外をスローするべきではありませんが、「純粋なセット」ではないコレクションがある場合は、適切な場所で例外スローする必要があります

より自然で一貫性のあることを常に行う必要があります。私にとっては、セットはセットルールに従う必要がありますが、セットではないものには適切に考えられたルールが必要です。

あなたの場合、それは良いアイデアのようです:

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;
}

しかし、これは本当に良い考えではありません。実行時にランダムに発生する可能性のある無効な状態になりましたが、それは問題に含まれているため、削除できません。例外をユーティリティメソッド内に移動できることを確認してください(同じコードを別の場所に移動します)が、それは間違っており、基本的にあなたができる最善のことは、通常のセット規則に固執することです。

実際には、linqクエリメソッドを書くことができることを示すために新しい複雑さを追加することはあなたの問題には価値がないようです、OPがドメインについてもっと教えてくれるなら、おそらく例外が本当に必要な場所を見つけることができると確信していますまったく問題が例外をまったく必要としない可能性があります)。


問題は、数学的に定義されたオブジェクトを使用して問題を解決しているが、問題自体が数学的に定義されたオブジェクトを回答として必要としない場合があることです(実際にはここにリストを返します)。カプセル化/情報隠蔽と呼ばれる、問題の解決方法に関係なく、すべてが問題の上位レベルに依存します。
GameDeveloper 16

あなたの「のsomeMethod」はもはやセットのように振る舞うべきではありませんその理由は、あなたが、具体的にコメントの部分を見て、「設定のうち、」情報の一部を尋ねる「&& someInputSet.NotEmpty()」されていることである
GameDeveloper

1
番号!女性のクラスで例外をスローすべきではありません。あなたがFemaleClass女性だけを持っていない限りインスタンスを取得することさえできないことを強制するBuilderパターンを使用する必要があります(それは公的に作成可能ではなく、Builderクラスのみがインスタンスを渡すことができます)、そしておそらくその中に少なくとも1人の女性がいます。次にFemaleClass、オブジェクトが間違った状態にあるため、引数として使用するコード全体で例外を処理する必要がありません。
エリック16

クラスは非常に単純であり、実際にはコンストラクターによって単純に前提条件を強制できると想定しています。あなたの議論には欠陥がある。もはや女性がいないことを禁じている場合、またはクラスから生徒を削除するメソッドがない場合、または1人の生徒が残っているときにメソッドが例外をスローする必要がある場合。あなたは私の問題を別の場所に移動したばかりです。重要なのは、「設計」で維持できない前提条件/機能状態が常に存在し、ユーザーが中断しようとしているということです:例外が存在する理由!これはかなり理論的なものです、私はダウン票があなたのものではないことを願っています。
GameDeveloper 16

ダウン票は私のものではありませんが、もしそうなら、私はそれを誇りに思うでしょう。私は慎重に、しかし確信を持って投票します。クラスのルールにアイテムが含まれている必要があり、すべてのアイテムが特定の条件を満たす必要がある場合、クラスを一貫性のない状態にすることは悪い考えです。問題を他の場所に移動するのはまさに私の意図です!私が欲しいの問題は建築時には、使用しない時に発生します。コンストラクターをスローする代わりにBuilderクラスを使用することのポイントは、矛盾を介して多くの部品や部品で非常に複雑な状態を構築できることです。
エリック16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.