VB のたまご

作成日: 2015/12/20, 更新日: 2015/12/20


拡張メソッドを使って、自分だけのサポート機能を追加しよう

事前チェックが面倒くさい

  •  コレクションデータを扱う際、いつもこんな感じで事前チェックを行っています。
  • Dim dt As New DataTable("sampleTable")
    dt.Columns.AddRange(New DataColumn() {
                        New DataColumn("ID", GetType(Integer)),
                        New DataColumn("Name", GetType(String))
                    })
    dt.Rows.Add(New Object() {1, "taro"})
    dt.Rows.Add(New Object() {DBNull.Value, DBNull.Value})
    dt.Rows.Add(New Object() {3, "jiro"})
    
    If dt IsNot Nothing AndAlso 0 < dt.Rows.Count Then
        For Each row As DataRow In dt.Rows
            Console.WriteLine("ID = {0}, Name = {1}", row.Field(Of Integer?)("ID"), row.Field(Of String)("Name"))
        Next
    End If
    
    Dim lst As New List(Of String) From {"a", "b", "c"}
    If lst IsNot Nothing AndAlso 0 < lst.Count Then
        For Each item In lst
            Console.WriteLine("item = {0}", item)
        Next
    End If
    
    If xxx IsNot Nothing AndAlso 0 < xxx.Count Then ' つまり、こんな感じ
    
    スポンサーリンク



  •  この事前チェックは、例外エラーを発生させないためにやっているのですが、正直面倒くさいです。2つチェック書くの。 こういう時は、チェック用のメソッドを準備すると楽です。
  • Function HasData(target As DataTable) As Boolean
    
        Return target IsNot Nothing AndAlso 0 < target.Rows.Count
    
    End Function
    
    Function HasData(Of T)(target As List(Of T)) As Boolean
    
        Return target IsNot Nothing AndAlso 0 < target.Count
    
    End Function
    
    If HasData(dt) Then
        For Each row As DataRow In dt.Rows
            Console.WriteLine("ID = {0}, Name = {1}", row.Field(Of Integer?)("ID"), row.Field(Of String)("Name"))
        Next
    End If
    
    If HasData(lst) Then
        For Each item In lst
            Console.WriteLine("item = {0}", item)
        Next
    End If
    

  •  うん、タイプするのが楽になりました。ただ、これでもいいのですが、あらかじめメソッドの事を知っていないと使えません。作成者は知っているかもしれませんが、他の人は知りません。 頑張ってみんなに周知するよりも、ToString メソッドのように、メソッドの事を知らなくても、インテリセンスを見て探して使うことができたらいいのに。 それと、xxx.ToString みたいな書き方だと、ドットでつなげて呼び出すという呼び出し方なので、その変数につながったもの、という印象を受けます。 普通のメソッドだと、一時的に用意しただけの独立したもの、という印象があります。 だから、できれば ToString メソッドみたいに書きたいのです。

スポンサーリンク


それなら、拡張メソッドを使おう!

  •  VB2008 から、拡張メソッドが使えるようになりました。拡張メソッドとは、簡単に言うと、既存の型に対してメソッドを追加できる機能です。 通常は、その型の中にメソッドを追加しないと使うことができません。 それが、拡張メソッドの場合は、部分クラスと同じように別ソースに書いても、その型のメソッドとして用意することができるようになります。 前節で書いた望みの書き方で、実際に書くことができるようになります。拡張メソッド、やばい。

  •  それではまず、拡張メソッド(メソッドを準備する側)を書いてみましょう。
  • Imports System.Runtime.CompilerServices
    
    Module CollectionExtensions
    
        <Extension()>
        Function HasData(target As DataTable) As Boolean
    
            Return target IsNot Nothing AndAlso 0 < target.Rows.Count
    
        End Function
    
        <Extension()>
        Function HasData(Of T)(target As List(Of T)) As Boolean
    
            Return target IsNot Nothing AndAlso 0 < target.Count
    
        End Function
    
    End Module
    

  •  拡張メソッドは、モジュールに書きます。普通のメソッドじゃなくて拡張メソッドなんですよ。と知らせるために、メソッドの頭に Extension 属性を付けます。 Extension は System.Runtime.CompilerServices 名前空間にありますので、インポートするのを忘れないでください。 必ず第一引数があり、第一引数には拡張したい型変数を書きます。 呼び出し時は、第一引数は含まないので、第二引数以降がある場合だけ、引数を受け取ることができます。

  •  次に使い方(メソッドを使う側)です。
  • If dt.HasData() Then
        For Each row As DataRow In dt.Rows
            Console.WriteLine("ID = {0}, Name = {1}", row.Field(Of Integer?)("ID"), row.Field(Of String)("Name"))
        Next
    End If
    
    If lst.HasData() Then
        For Each item In lst
            Console.WriteLine("item = {0}", item)
        Next
    End If
    

  •  そうそう、これこれ~。見た目もスッキリになりました。条件分岐がシンプルだと、良いですね、邪魔していない感じがします。

  •  最後までこの記事を読んでいただき、ありがとうございました。


スポンサーリンク