はじめに
本記事はC#においてリストから指定の型にキャストできる要素を取り出す方法をまとめます。
やりたいこと
基底クラスのリストから指定した派生クラスの型の要素を取り出す場合を考えてみます。
といっても具体例がないとイメージがわかないと思うので、以下のようにAnimal(動物)クラス、Vertebrate(セキツイ動物)クラス、Invertebrate(無セキツイ動物)クラスの関連がある際に、基底クラス(Animalクラス)型のリストから派生クラス(Vertebrateクラス)型の要素を取り出したい場合を考えます。

最初に思いついた実装案
十分に実現方法を調べない状態で筆者が実装したコードは以下でした。
// 動物一覧を作成
var animals = new List<Animal>();
animals.Add(new Vertebrate(){Name = "人間"});
animals.Add(new Vertebrate(){Name = "犬"});
animals.Add(new Vertebrate(){Name = "猫"});
animals.Add(new Invertebrate(){Name = "イカ"});
animals.Add(new Invertebrate(){Name = "タコ"});
// セキツイ動物を取得
var vertebrates = animals.Where(animal => animal is Vertebrate).Select(animal => (Vertebrate)animal);
WhereメソッドでVertebrate型の要素を抽出し、抽出した要素をSelectメソッドでVertebrate型にキャストするといったコードになります。
コードを書いた時点から、Linq文が長いので、もっと簡潔に記載できる方法はないかなと思っていました。
調べてみるとOfTypeメソッドでやりたいことがより簡潔に書けることがわかりました。
OfTypeメソッドを使う場合
OfTypeメソッドはIEnumerableのシーケンス要素から指定した型にキャストできる要素のみを取り出すメソッドになります。
まさに今回やりたいことを実現するのに適したメソッドになります。
前章のコードをOfTypeメソッドを利用するように書き換えると以下のようになります。
// 動物一覧を作成
var animals = new List<Animal>();
animals.Add(new Vertebrate(){Name = "人間"});
animals.Add(new Vertebrate(){Name = "犬"});
animals.Add(new Vertebrate(){Name = "猫"});
animals.Add(new Invertebrate(){Name = "イカ"});
animals.Add(new Invertebrate(){Name = "タコ"});
// セキツイ動物を取得
// OfTypeメソッドを使うことで変数animalsからVertebrate型の要素を取り出していることが一目でわかるようになる
var vertebrates = animals.OfType<Vertebrate>();
OfTypeメソッドを使うことでLinq文が短くなり、変数animalsからVertebrate型の要素を取り出していることが一目で分かるようになりました。
やはり、何かを実装する際にはより適切な実現方法がないかに常に関心を持ち、調べることが重要だなと再認識しました。
まとめ
本記事はC#においてリストから指定の型にキャストできる要素を取り出す方法をまとめました。
始めは、WhereメソッドとSelectメソッドを組み合わせて実現していましたが、OfTypeメソッドを使うことでコードを見ただけですぐにリストから指定の型にキャストできる要素を取り出しているのだと分かるようになりました。
やはり、より最適な実装方法に常に関心を持ち、調べることが重要だと再認識しました。この考えはこれからも持ち続けていきたいです。