C#のLINQの関数であるOfType()
の使い方についてです。
配列やリストなどのシーケンス内にて、指定した型に変換できる要素を取得することが出来ます。
この記事には.NET Framework 4.6.1を使用しています。
この型に変換できる要素はあるのかな
とあるクラスを継承したクラスがたくさんあり、そのデータの管理に一番ベースとなっているクラスのリストをデータとして持つ。
そんなときありますよね。
でもその中で特定のクラスのデータのみが欲しい場合はありませんか。
そんなときはLINQのOfType()
が便利です。
欲しい方をジェネリックで指定すれば、変換可能な要素のみを取得できます。
public static IEnumerable<TResult> OfType<TResult>( this IEnumerable source );
Enumerable.OfType(TResult) メソッド (IEnumerable) (System.Linq)
早速以下の例で試してみましょう。
以下の例ではクラス構成がこんな感じになっています。
……クラス図あっているかな。
このクラスに対して、OfType()
を使ってみましょう。
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { private class BaseClass { public virtual string Type { get { return "-"; } } public string Name { get; set; } public override string ToString() { return string.Format( "Type:{0}, Name:{1}", Type, Name ); } } private class ClassA : BaseClass { public override string Type { get { return "A"; } } } private class ClassB : BaseClass { public override string Type { get { return "B"; } } } private class ClassC : ClassB { public override string Type { get { return "C"; } } } static void Main( string[] args ) { BaseClass[] parameters = new BaseClass[] { new ClassA() { Name = "正一郎" }, new ClassB() { Name = "清次郎" }, new ClassB() { Name = "誠三郎" }, new ClassC() { Name = "征史郎" }, }; // 各クラスに変換 IEnumerable<BaseClass> reaultBase = parameters.OfType<BaseClass>(); IEnumerable<ClassA> reaultA = parameters.OfType<ClassA>(); IEnumerable<ClassB> reaultB = parameters.OfType<ClassB>(); IEnumerable<ClassC> reaultC = parameters.OfType<ClassC>(); // 結果発表 System.Console.WriteLine( "parameters:{0}", parameters.Text() ); System.Console.WriteLine( "BaseClassに変換できるもの:{0}", reaultBase.Text() ); System.Console.WriteLine( "ClassAに変換できるもの :{0}", reaultA.Text() ); System.Console.WriteLine( "ClassBに変換できるもの :{0}", reaultB.Text() ); System.Console.WriteLine( "ClassCに変換できるもの :{0}", reaultC.Text() ); // 入力待ち用 System.Console.ReadKey(); } /// <summary> /// 簡易的なシーケンスのテキスト取得処理 /// </summary> public static string Text<TSource>( this IEnumerable<TSource> i_source ) { string text = string.Empty; foreach( var value in i_source ) { text += string.Format( "[{0}], ", value ); } return text; } } // class Program
parameters:[Type:A, Name:正一郎], [Type:B, Name:清次郎], [Type:B, Name:誠三郎],
[Type:C, Name:征史郎],
BaseClassに変換できるもの:[Type:A, Name:正一郎], [Type:B, Name:清次郎], [Type:B,
Name:誠三郎], [Type:C, Name:征史郎],
ClassAに変換できるもの :[Type:A, Name:正一郎],
ClassBに変換できるもの :[Type:B, Name:清次郎], [Type:B, Name:誠三郎], [Type:C,
Name:征史郎],
ClassCに変換できるもの :[Type:C, Name:征史郎],
こんな感じに使えます。
他にもArrayList
に対しても使えます。
ArrayList
にはいろんな型のものを渡せるので便利ではあるのですが、データが混沌としやすいです。
ではOfType()
を使って各型の要素を取得してみましょう。
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { static void Main( string[] args ) { // いろんな型が入ったデータ ArrayList list = new ArrayList() { 1, 3, "2", 5.5f }; // 各クラスに変換 IEnumerable<int> reaultInt = list.OfType<int>(); IEnumerable<string> reaultString = list.OfType<string>(); IEnumerable<float> reaultFloat = list.OfType<float>(); IEnumerable<long> reaultLong = list.OfType<long>(); // 結果発表 System.Console.WriteLine( "list:{0}", list.Text() ); System.Console.WriteLine( "intに変換できるもの :{0}", reaultInt.Text() ); System.Console.WriteLine( "stringに変換できるもの:{0}", reaultString.Text() ); System.Console.WriteLine( "floatに変換できるもの :{0}", reaultFloat.Text() ); System.Console.WriteLine( "longに変換できるもの :{0}", reaultLong.Text() ); // 入力待ち用 System.Console.ReadKey(); } /// <summary> /// 簡易的なシーケンスのテキスト取得処理 /// </summary> public static string Text( this IEnumerable i_source ) { string text = string.Empty; foreach( var value in i_source ) { text += string.Format( "[{0}], ", value ); } return text; } } // class Program
list:[1], [3], [2], [5.5],
intに変換できるもの :[1], [3],
stringに変換できるもの:[2],
floatに変換できるもの :[5.5],
longに変換できるもの :
こんな感じで取得できます。
……まあコード上でこのようなデータは作らないとは思いますが、外部から情報を取得する場合には使うこともあると思います。
こんな感じでOfType()
を七兆回ほど使ってみてください。
LINQのリンク
LINQ一覧
www.urablog.xyzCast
指定した型のシーケンスに変換したい!
www.urablog.xyz