技術解説 .NET 2.0 ジェネリック(Generics) 第3回 List<T>.FindAll(Predicate<T>)
2006/01/26
この文書はVisual Studio 2005をベースに記述されています。
第3回 List<T>.FindAll(Predicate<T>)
今回はFindAllをはじめとするFind系メソッドだ。
あるArrayListに入っているデータの文字列が、数字の場合に別のArrayListに構築する想定だ。
まずは従来型のソースを見てもらおう。
1.x C# ArrayList al = new ArrayList(); al.Add("1"); al.Add("B"); al.Add("3"); ArrayList al2 = new ArrayList(); foreach( string text in al) { try { int.Parse(text); al2.Add(text); } catch { } }
1.x VB Dim al As ArrayList = New ArrayList al.Add("1") al.Add("B") al.Add("3") Dim al2 As ArrayList = New ArrayList For Each text As String In al Try Int32.Parse(text) al2.Add(text) Catch ex As Exception End Try Next
1.x MC++ ArrayList __gc *al = new ArrayList(); al->Add(S"1"); al->Add(S"B"); al->Add(S"3"); ArrayList __gc *al2 = new ArrayList(); for ( int LoopCounter = 0; LoopCounter < al->Count; LoopCounter++ ) { try { Int32::Parse(static_cast<String*>(al->Item[LoopCounter])); al2->Add(static_cast<String*>(al->Item[LoopCounter])); } catch(Exception*) { } }
従来のコーディングであれば、やはり一つ一つArrayListから取り出して評価していくことになる。
この場合取り出すべきデータなのか、そうでないのかというのは例外のキャッチで表現されているので、なんとなくわかるが、true/falseといった形で明確になっていない。
場合によってはExceptionで何か他の例外が発生するのでそれを捕まえるためかと思われてしまう。
2.0 C# private void button1_Click(object sender, EventArgs e) { List<string> ls = new List<string>(); ls.Add("1"); ls.Add("B"); ls.Add("3"); Predicate<string> numsel = new Predicate<string>(NumericSelector); List<string> ls2 = ls.FindAll(numsel); } public bool NumericSelector(string text) { try { int.Parse(text); return true; } catch (FormatException) { return false; } }
2.0 VB Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim ls As List(Of String) = New List(Of String) ls.Add("1") ls.Add("B") ls.Add("3") Dim numsel As Predicate(Of String) = New Predicate(Of String)(AddressOf NumericSelector) Dim ls2 As List(Of String) = ls.FindAll(numsel) End Sub Public Function NumericSelector(ByVal text As String) As Boolean Try Int32.Parse(text) Return True Catch ex As Exception Return False End Try End Function
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { List<String^>^ ls = gcnew List<String^>(); ls->Add("1"); ls->Add("B"); ls->Add("3"); Predicate<String^>^ numsel = gcnew Predicate<String^>(this, &Form1::NumericSelector); List<String^>^ ls2 = ls->FindAll(numsel); } public : bool NumericSelector(String^ text) { try { Int32::Parse(text); return true; } catch(Exception^) { return false; } }
このように一部のデータを抜き出すということ(FindAll)にこのような処理を行うということがより明確になっていると思う。
このPredicateデリゲートは
delegate bool Predicate(<T>)
となっており、YesかNoかの判定に使われる。
List<T>の中で利用されているのは
.Exists
.Find
.FindAll
.FindIndex
.FindLast
.FindListIndex
.RemoveAll
.TrueForAll
と多用されている。
ちなみにArrayにも同様に採用されているので、単純な配列でも同様の処理が可能だ。
おまけの匿名メソッド版の場合には記述が離れた位置にならないため、よりわかりやすい記述になる。
2.0 C#(匿名メソッドを使った場合) private void button1_Click(object sender, EventArgs e) { List<string> ls = new List<string>(); ls.Add("1"); ls.Add("B"); ls.Add("3"); List<string> ls2 = ls.FindAll(delegate(string text) { try { int.Parse(text); return true; } catch (FormatException) { return false; } }); }