前回に引き続き、変換演算子についてです。
今回は、OfTypeメソッドです。
OfTypeメソッドは、対象となるシーケンスを特定の型のみのシーケンスに
変換するメソッドです。
OfTypeメソッドの書式は、以下のようになっています。
public static IEnumerable<TResult> OfType<TResult>( this IEnumerable source )
IEnumerable
定義されています。これにより、このメソッドは、Genericではないシーケンスに対しても
利用出来ます。
例えば、基底クラスとしてPersonクラスが存在し
派生クラスとしてCustomerクラスが存在するとします。
そして、List
Customerオブジェクトの両方が設定されている状態で
persons.OfType<Customer>();
とすると、Customerオブジェクトのみのリストが取得できます。
よく利用するのが、GenericではないArrayListなどをIEnumerable
// // 元々GenericではないリストをIEnumerable<T>に変換する場合にも利用出来る. // ArrayList arrayList = new ArrayList(); arrayList.Add(10); arrayList.Add(20); arrayList.Add(30); arrayList.Add(40); IEnumerable<int> intList = arrayList.OfType<int>(); foreach (var data in intList) { Console.WriteLine(data); }
以下、サンプルです。
#region LinqSamples-16 public class LinqSamples16 : IExecutable { class Person { public int Id { get; set; } public string Name { get; set; } } class Customer : Person { public IEnumerable<Order> Orders { get; set; } } class Order { public int Id { get; set; } public int Quantity { get; set; } } public void Execute() { List<Person> persons = new List<Person> { new Person { Id = 1, Name = "gsf_zero1" } ,new Person { Id = 2, Name = "gsf_zero2" } ,new Customer { Id = 3, Name = "gsf_zero3", Orders = Enumerable.Empty<Order>() } ,new Customer { Id = 4 ,Name = "gsf_zero4" ,Orders = new List<Order> { new Order { Id = 1, Quantity = 10 } ,new Order { Id = 2, Quantity = 2 } } } ,new Person { Id = 5, Name = "gsf_zero5" } }; // // OfTypeメソッドを利用することにより、特定の型のみのシーケンスに変換することができる。 // 例えば、リストの中に基底クラスであるPersonクラスと派生クラスであるCustomerクラスの // オブジェクトが混在している場合、OfType<Person>とすると、そのまま。 // OfType<Customer>とすると、Customerオブジェクトのみのシーケンスに変換される。 // // // 尚、OfTypeメソッドは他の変換演算子とは違い、ソースシーケンスのスナップショットを作成しない。 // つまり、通常のクエリと同じく、OfTypeで取得したシーケンスが列挙される度に評価される。 // 変換演算子の中で、このような動作を行うのはAsEnumerableとOfTypeとCastとなる。 // Console.WriteLine("========== OfType<Person>の結果 =========="); foreach (var data in persons.OfType<Person>()) { Console.WriteLine(data); } Console.WriteLine("========== OfType<Customer>の結果 =========="); foreach (var data in persons.OfType<Customer>()) { Console.WriteLine(data); } // // 元々GenericではないリストをIEnumerable<T>に変換する場合にも利用出来る. // ArrayList arrayList = new ArrayList(); arrayList.Add(10); arrayList.Add(20); arrayList.Add(30); arrayList.Add(40); Console.WriteLine("========== Genericではないコレクションを変換 =========="); foreach (var data in arrayList.OfType<int>()) { Console.WriteLine(data); } } } #endregion
結果は以下のようになります。
========== OfTypeの結果 ========== Gsf.Samples.LinqSamples16+Person Gsf.Samples.LinqSamples16+Person Gsf.Samples.LinqSamples16+Customer Gsf.Samples.LinqSamples16+Customer Gsf.Samples.LinqSamples16+Person ========== OfType の結果 ========== Gsf.Samples.LinqSamples16+Customer Gsf.Samples.LinqSamples16+Customer ========== Genericではないコレクションを変換 ========== 10 20 30 40
追記:
書き忘れてました。
OfTypeメソッドは、他の変換演算子と違い、ソースシーケンスのスナップショットを作成しません。
つまり、
IEnumerable<Customer> c = persons.OfType<Customer>();
として取得した、シーケンスcを列挙(ループ)する度に評価されます。