前回に引き続き、変換演算子についてです。
今回は、Castメソッドです。
Castメソッドは、OfTypeメソッドとほとんど一緒です。
違いは、OfTypeメソッドでは変換対象となる型ではないオブジェクトは
除外されますが、Castメソッドの場合InvalidCastExceptionが発生します。
Castメソッドの書式は、以下のようになっています。
public static IEnumerable<TResult> Cast<TResult>( this IEnumerable source )
IEnumerable
定義されています。これにより、このメソッドは、Genericではないシーケンスに対しても
利用出来ます。
例えば、基底クラスとしてPersonクラスが存在し
派生クラスとしてCustomerクラスが存在するとします。
そして、List
Customerオブジェクトの両方が設定されている状態で
persons.Cast<Customer>();
とすると、OfTypeメソッドではCustomerのみのシーケンスとなりますが
Castメソッドの場合は例外が発生します。
尚、OfTypeメソッドと同じくCastメソッドもソースシーケンスのスナップショットを作成しません。
Castメソッドの結果は、通常のLinqクエリと同じく列挙(ループ)の際に評価されます。
なので、
IEnumerable<Person> p = persons.Cast<Person>();
とした後で、元のシーケンスに対して
persons.Add(new Person()); foreach (var tmp in p) { Console.WriteLine(tmp); }
とすると、後で追加したオブジェクトも列挙されます。
以下、サンプルです。
#region LinqSamples-17 public class LinqSamples17 : 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" } }; // // Castメソッドを利用することにより、特定の型のみのシーケンスに変換することができる。 // OfTypeメソッドと違い、Castメソッドは単純にキャスト処理を行う為、キャスト出来ない型が // 含まれている場合は例外が発生する。 // (OfTypeメソッドの場合、除外される。) // // // 尚、Castメソッドは他の変換演算子とは違い、ソースシーケンスのスナップショットを作成しない。 // つまり、通常のクエリと同じく、Castで取得したシーケンスが列挙される度に評価される。 // 変換演算子の中で、このような動作を行うのはAsEnumerableとOfTypeとCastである。 // Console.WriteLine("========== Cast<Person>の結果 =========="); foreach (var data in persons.Cast<Person>()) { Console.WriteLine(data); } ////////////////////////////////////////////////////////// // // 以下のpersons.Cast<Customer>()はPersonオブジェクトをCustomerオブジェクトに // キャスト出来ない為、例外が発生する。 // Console.WriteLine("========== Cast<Customer>の結果 =========="); try { foreach (var data in persons.Cast<Customer>()) { Console.WriteLine(data); } } catch(InvalidCastException ex) { Console.WriteLine(ex.Message); } // // 元々GenericではないリストをIEnumerable<T>に変換する場合にも利用出来る. // 当然、Castメソッドを利用する場合は、コレクション内部のデータが全てキャスト可能で // ないといけない。 // ArrayList arrayList = new ArrayList(); arrayList.Add(10); arrayList.Add(20); arrayList.Add(30); arrayList.Add(40); Console.WriteLine("========== Genericではないコレクションを変換 =========="); IEnumerable<int> intList = arrayList.Cast<int>(); foreach (var data in intList) { Console.WriteLine(data); } } } #endregion
結果は以下のようになります。
========== Castの結果 ========== Gsf.Samples.LinqSamples17+Person Gsf.Samples.LinqSamples17+Person Gsf.Samples.LinqSamples17+Customer Gsf.Samples.LinqSamples17+Customer Gsf.Samples.LinqSamples17+Person ========== Cast の結果 ========== 型 'Person' のオブジェクトを型 'Customer' にキャストできません。 ========== Genericではないコレクションを変換 ========== 10 20 30 40