バックエンドエンジニアの大和道子です
今回は私が C# を使い始めて最初のころに迷った First と FirstOrDefault。OfType と Cast についての勉強メモをご紹介します。
はじめに
読むのにかかる時間:3分
経緯:「常にFirstOrDefaultを使うべき」という記事を見たため
「これが正解」というブログは信じない
→常に、最も適切なメソッドを使うという原則こそが「正解」である
前提知識
・First
First
シーケンス.First(); //シーケンスの最初の要素を返す
シーケンス.First((要素) => 評価式); //条件に当てはまるシーケンスの最初の要素を返す
*見つからなかった場合は、例外を吐く
・FirstOrDefault
「シーケンス.FirstOrDefault();」:シーケンスの最初の要素を返す
「シーケンス.FirstOrDefault((要素) => 評価式);」:条件に当てはまるシーケンスの最初の要素を返す
*見つからなかった場合は、初期値を返す(nullなど)
記事の主張
「Firstで要素が見つからなければ、エラーを吐いて止まるので、FirstOrDefaultを使う方が正解」
➡ (反論)FirstOrDefaultを使いまくることは危険である
例えば、自分が値を入れているつもりの配列に値が入っていないバグがあるコードを書いちゃったとき…
①Firstを使う
→エラーを吐くので、その場でバグに気付ける
②FirstOrDefaultを使う
→nullでコードが進むので、バグに気付くのが遅くなる
(結論)適切なところで、例外を投げるほうが安全性が高い!!
ついでに
・同記事で、「Castは変換できないときに例外を吐くけど、OfTypeはnull以外の例外を出さないから安全」と主張されていたので
・想定例:Formアプリケーションで、コントロールを配置して、Button型だけほしいとき
・OfType
Controls.OfType<Button>()~
//Controlsの中で、Button型のControlのみを抽出してEnumerableを返す
//(色んな型が入ってるものを取ってきて、特定の型を抽出する)
・Cast
Controls.Cast<Button>()~
//Control型で取ってきたControlsをEnumerable<Button>にする
//(特定の型の配列を型変換する)
(結論)用途が違う
・Control型で取ってきたシーケンスの全ての要素がButtonであるときはCast
・コントロールの抽出がしたいときはOfType
が基本だが、コントロール配置は変更される可能性があるため、上記の想定例ではOfTypeを使うことが普通だと思います。