5

注: 下部の編集を参照してください。私はばかです。

タグ名のセットを処理し、新しいものを識別/処理する次のコードがありました

IEnumberable<string> tagNames = GetTagNames();
List<Tag> allTags = GetAllTags();

var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name == n));

foreach (var tagName in newTagNames)
{
    // ...
}

...そしてこれはうまくいきましたが、「Foo」というタグがあり、リストに「foo」が含まれている場合を処理できませんでした。つまり、大文字と小文字を区別しない比較を行っていませんでした。

次のように、大文字と小文字を区別しない比較を使用するようにテストを変更しました。

var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase)));

...そして突然、foreach が実行された (そして MoveNext が呼び出された) newTagNames のときに例外がスローされます。例外は言う:

シーケンスに要素がありません

私はこれに混乱しています。foreachシーケンスが空でないことを主張するのはなぜですか? を呼び出している場合はそのエラーが表示されると予想されますが、 ?First()を使用している場合はそうではありません。foreach


編集:詳細。

これは分ごとに奇妙になっています。私のコードは非同期メソッドであり、私は迷信的であるため、例外が発生したポイントと、例外がキャッチされて報告されるポイントとの間に「距離」がありすぎると判断しました。そのため、スローされた例外が実際に私が思っていたものであることを確認するために、問題のあるコードの周りに try/catch を配置しました。

これで、デバッガーで foreach 行までステップ実行し、シーケンスが空であることを確認し、デバッガーが "in" という単語を強調表示するビットまでステップアップできます。もう 1 ステップで、例外ハンドラーに入ります。

しかし、先ほど追加した例外ハンドラではありません。最近追加されたものにアクセスせずに、最も外側の例外ハンドラーに着陸します! 一致catch (Exception ex)しませんし、プレーンとも一致しませんcatch。(私も入れましたfinally、そしてそれが途中でそれを訪問することを確認しました)。

私は常に、これらのような例外ハンドラーが例外をキャッチすると信じてきまし。私は今怖いです。大人が必要です。


編集2

わかりました、そうです、誤報です...例外は、私が考えていたコードによって発生していなかったという理由だけで、ローカルのtry/catchによってキャッチされていませんでした。上で述べたように、デバッガーでの実行がforeachストレートの「in」から外側の例外ハンドラーにジャンプするのを見たので、エラーが発生した場所であるという私の (間違った) 仮定。ただし、空の列挙では、それは単に関数内で実行された最後のステートメントであり、何らかの理由で、デバッガーは関数からのステップアウトまたは呼び出し時点での次のステートメントの実行を表示しませんでした。実際にエラーを引き起こしたもの。

回答してくれたすべての人に謝罪し、私がばかだと言って回答を作成したい場合は、喜んで受け入れます. つまり、またSOに顔を出したら…

4

2 に答える 2

0

それは適切でもきれいでもありませんが、これはどのように機能しますか:

var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.ToUpper() == n.ToUpper()));
于 2012-11-14T17:57:43.710 に答える
0

遅延アクションでの例外処理は楽しいものです。Enumerable.Where メソッド (およびほとんどの linq メソッド) は、クエリが列挙されるまで実行されません。

IEnumerable<int> query = Enumerable.Empty<int>();
int myNum = 0;
try
{
  query = Enumerable.Range(1, 100).Where(i => (i/myNum) > 1);
}
catch
{
  Console.WriteLine("I caught divide by zero"); //does not run
}

foreach(int i in query) //divide by zero exception thrown
{
  //..
}

あなたの特定のケースでは:

IEnumberable<string> tagNames = GetTagNames();

GetTagNamesどこかに Enumerable.First または Enumerable.Single があるに違いありません。GetTagNames の結果が遅延された場合、その結果を列挙して例外を発生させる必要があります。そのため、コメンターは、GetTagNames の結果に対して ToList を呼び出すことを推奨しています。これを列挙して、複雑なクエリで tagNames を使用する前に発生する例外を取得します。

于 2012-11-14T19:59:36.170 に答える