fc2ブログ

VB文法リファレンス - タイプコンストラクタ

概要
 型共通の初期化処理を定義します。デフォルトコンストラクタと似ていますが、デフォルトコンストラクタは、インスタンスの初期化ですので違う機能です。

使用に適した状況
 型に共通して存在する初期化処理が必要な場合。インスタンスごとに必要な処理か、型に必要な処理なのかをよく考えて使い分ける必要があります。

サンプル

'-------------------------------------------------------

'コンストラクタ

'-------------------------------------------------------
Imports System

Class ReferenceType

    Public Value As Integer
    Public Shared BaseValue As Integer

    Shared Sub New()
        BaseValue = 10 '静的な変数などを初期化
        Console.WriteLine("参照型のタイプコンストラクタが呼び出されました。")
    End Sub

    Public Overrides Function ToString() As String
        Return "値は" & (Me.Value + BaseValue).ToString()
    End Function

End Class

Structure ValueType

    Public Value As Integer
    Public Shared BaseValue As Integer

    Shared Sub New()
        BaseValue = 10 '静的な変数などを初期化
        Console.WriteLine("値型のタイプコンストラクタが呼び出されました。")
    End Sub

    Public Overrides Function ToString() As String
        Return "値は" & (Me.Value + BaseValue).ToString()
    End Function

End Structure

Module Sample

    Sub Main()

        '参照型のタイプコンストラクタ
        Console.WriteLine("参照型のタイプコンストラクタは呼び出されるかな?")
        Dim r As ReferenceType() = New ReferenceType(10) {}
        r(0) = New ReferenceType() 'Nullに初期化されている
        r(0).Value = 10
        Console.WriteLine("参照しなくてもタイプコンストラクタは呼び出さられる。")
        Console.WriteLine(r(0).ToString() & vbNewLine)

        '値型のタイプコンストラクタの挙動は難しいので避けるべき
        Console.WriteLine("値型のタイプコンストラクタは呼び出さられるかな?")
        Dim v As ValueType() = New ValueType(10) {}
        'v(0) = new ValueType( ) '値型は必要ない
        v(0).Value = 100
        Console.WriteLine("あれ?参照してみよう。")
        '値型のタイプコンストラクタ派参照すると呼び出される
        Console.WriteLine(v(0).ToString() & vbNewLine)

        '終了
        Console.WriteLine("終了")
        Console.ReadLine()

    End Sub

End Module


文法
 静的指定している点と、アクセス修飾子が指定できず、規定でprivateになる点を除けば、デフォルトコンストラクタと同じ文法です。文法的には似ていますが、全く違う内容を表わしているので十分に注意してください。

解説
 インスタンスではなく、型を対象にした初期化処理が必要な場合があります。例えば、型に属する変数の初期化処理や、環境の準備などが必要な場合、タイプコンストラクタを使用します。インスタンスごとに行う初期化なのか、型に対して行う初期化処理なのかは、十分に設計しておく必要があります。
 注意するべき点は、参照型と値型の挙動が違う点です。参照型と値型はメモリ配置の形式が異なりますので、タイプコンストラクタの実行されるタイミングが異なります。特に値型は参照型よりもルールが複雑なので、極力値型のタイプコンストラクタの定義は避けるべきだと思います。もしどうしても必要ならば、必ず検証作業をしておくべきでしょう。そうしないと、発見困難なエラーに悩まされる羽目になるかもしれません。
スポンサーサイト



テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - デフォルトコンストラクタ

概要
 インスタンスの初期処理を設定したい場合に使用します。ただし、指定していない場合もコンパイラが自動で生成します。

使用に適した状況
 コンパイラが自動で生成するので、自分の意図を示すために、デフォルトコンストラクタを常に定義する方が良いでしょう。ただし、デフォルトコンストラクタが必要なく、常にコンストラクタで値を指定し、インスタンスを生成する、何らかの制約を持つオブジェクトは別です。そのようなオブジェクトでは、デフォルトコンストラクタを指定しない方が良いでしょう。

サンプル

'-------------------------------------------------------

'デフォルトコンストラクタ

'-------------------------------------------------------
Imports System
Imports System.Reflection


Class Sample : End Class
MustInherit Class AbstractClass : End Class
Module StaticClass : End Module

Structure Value : End Structure
Class Foo

    'デフォルトコンストラクタ
    Public Sub New()
        Console.WriteLine("自分で定義したデフォルトコンストラクタを呼び出しました。")
    End Sub

End Class

Structure Bar

    '値型はデフォルトコンストラクタを定義できない
    'Public Sub New()
    '    Console.WriteLine("呼び出されません")
    'End Sub
End Structure

Module Constructor

    Sub Main()

        '何も指定しない場合、デフォルトコンストラクタが自動生成される。
        Console.WriteLine("参照型のデフォルトコンストラクタ")
        PrintInfo(GetType(Sample))
        Console.WriteLine()

        '自分で実装した場合
        Console.WriteLine("自分で用意した参照型のデフォルトコンストラクタ")
        PrintInfo(GetType(Foo))
        Console.WriteLine()

        Dim obj As Foo = New Foo()
        Console.WriteLine()

        '抽象クラスのデフォルトコンストラクタ
        Console.WriteLine("抽象型のデフォルトコンストラクタ")
        PrintInfo(GetType(AbstractClass))
        Console.WriteLine()

        '静的クラスのデフォルトコンストラクタ
        '※静的クラスはデフォルトコンストラクタは存在しない
        Console.WriteLine("静的クラスのデフォルトコンストラクタ")
        PrintInfo(GetType(StaticClass))
        Console.WriteLine()

        '値型
        Console.WriteLine("値型のデフォルトコンストラクタ")
        PrintInfo(GetType(Value))
        Console.WriteLine()

        '終了
        Console.ReadLine()

    End Sub

    Private Sub PrintInfo(ByVal type As Type)
        Dim count As Integer = 0
        For Each info As ConstructorInfo In type.GetConstructors(
            BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Instance)
            Console.WriteLine("アクセス修飾子はPublic?{0}", info.IsPublic)
            Console.WriteLine("アクセス修飾子はProtected?{0}", info.IsFamily)
            Console.WriteLine(info.ToString())
            count += 1
        Next
        If count = 0 Then
            Console.WriteLine("コンストラクタは存在しません。")
        End If
    End Sub

End Module


文法
 引数を受け取らないコンストラクタであり、Newという名前のサブルーチンのような形式です。文法的には簡単ですが、型の種類ごとにルールの細部は異なります。それに加えて、設計レベルから考える必要があります。ずいぶん簡単に見える文法ですが、使いこなすのは結構難しいです。

解説
 オブジェクト指向設計により、オブジェクトの初期処理がある場合デフォルトコンストラクタを使用します。しかしながら、厳密に初期処理を必要としないオブジェクトは存在しません。コンピュータ上で動く以上、メモリ領域の割り当てなどの処理が必要です。ですから、常にコンストラクタで値を指定しなければ、インスタンスを生成できない、ある一定の制約を持つオブジェクト以外に使用します。
 自分で定義しないと、コンパイラが自動でデフォルトコンストラクタを用意してくれますが、それでは定義忘れなのか、意図的なのかがわかりません。従って、制約上必要がないとはっきりしているとき以外は必ず自分で定義しましょう。
 サンプルプログラムで示したように、参照型と値型ではデフォルトコンストラクタの扱いが異なります。値型はデフォルトコンストラクタを定義できません。従って、厳密にインスタンスを制御する必要がある場合は、参照型にする必要があります。
 その他にも、静的クラスや抽象クラスでもデフォルトコンストラクタのルールが異なります。つまり、型の類ごとにルールが異なるのです。発見しにくいエラーの元になるので、十分に気を付けてください。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - コンストラクタ

概要
 簡潔に初期値を待ったインスタンスを生成します。

使用に適した状況
 インスタンスに何らかの初期値を設定したい場合。

サンプル

'-------------------------------------------------------

'コンストラクタ

'-------------------------------------------------------
Imports System

Public Class Foo

    'プロパティ
    Public Property Value As Integer

    'コンストラクタ
    Public Sub New(ByVal newValue As Integer)
        If newValue < 0 Then
            Throw New ArgumentException("0以上の値を指定してください。")
        End If
        Me.Value = newValue
    End Sub

End Class

Module Sample

    Sub Main()

        'コンストラクタで初期値を設定する
        Dim value As Integer = 10
        Dim obj As Foo = New Foo(value)
        Console.WriteLine("初期値{0}を指定してインスタンスを作成します。", value)
        Console.WriteLine("インスタンスの値は{0}です。", obj.Value)

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 コンストラクタは、Newという名前のサブルーチンの形式です。引数を何も指定しないコンストラクタを、デフォルトコンストラクタと呼びます。デフォルトコンストラクタは、コンストラクタと少し内容が異なりますので、デフォルトコンストラクタについては別に紹介します。

解説
 プログラミングをしているとき、何らかの値を持ったインスタンスを作成したい場合が多々あります。コンストラクタがないプログラミング言語は、変数を作成し多直後に、いちいち値を設定するプログラムをセットで書かねばなりませんでした。しかし、そのような定型作業は、面倒かつプログラムの量を無暗に増やし、正しく行わないとエラーを発生させます。そのような、煩雑かつ、エラーの元となる定型作業を簡潔化するために、コンストラクタは存在します。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス ー プロパティ

概要
 データを安全に読み書きするための文法です。読み取り専用、もしくは書き込み専用に設定できます。

使用に適した状況
 ほぼすべての状況。オブジェクト指向プログラミングをする上で、なくてはならない存在です。

サンプル

'----------------------------------------------------
' 
'  プロパティ
'  
'----------------------------------------------------
Imports System
Imports System.Text

Class Sample

    'プロパティ
    Private _value As Integer
    Public Property Value As Integer
        Get
            Return Me._value
        End Get
        Set(value As Integer)
            If value >= 0 Then
                Me._value = value
            Else
                Throw New ArgumentOutOfRangeException("0未満の数値は指定できません。")
            End If
        End Set
    End Property

    '読み取り専用プロパティ
    Private _id As Integer
    Public ReadOnly Property ID As Integer
        Get
            Return Me._id
        End Get
    End Property

    '書きこみ専用プロパティ
    Private _name As String 'フィールド
    Public WriteOnly Property Name As String
        Set(value As String)
            Me._name = Value
        End Set
    End Property

    'アクセス修飾子を変更
    Public Property Zero As Integer
        Get
            Return 0
        End Get
        Private Set(value As Integer)
        End Set
    End Property

    '確認用メソッド
    Public Overrides Function ToString() As String

        'インデクサ以外のプロパティの値を文字列にする
        Dim result As StringBuilder = New StringBuilder()

        result.Append("Value = ")
        result.Append(Me._value)
        result.Append(Environment.NewLine)

        result.Append("ID = ")
        result.Append(Me.ID)
        result.Append(Environment.NewLine)

        result.Append("Name = ")
        result.Append(Me._name)
        result.Append(Environment.NewLine)

        result.Append("Zero = ")
        result.Append(Me.Zero)
        result.Append(Environment.NewLine)

        '生成した文字列を返す
        Return result.ToString()
    End Function
End Class

Module Program

    Sub Main()

        '準備
        Dim obj As Sample = New Sample()

        'プロパティを使用
        Console.WriteLine("変更前の状態・・・")
        Console.WriteLine(obj.ToString())
        obj.Value = 10
        Console.WriteLine("変更後の状態・・・")
        Console.WriteLine(obj.ToString())

        '読み取り専用プロパティを使用
        Console.WriteLine("ID = 0", obj.ID)
        Console.WriteLine()

        '書き込み専用プロパティを使用
        Console.WriteLine("名前を間違った!")
        obj.Name = "山田花子"
        Console.WriteLine(obj.ToString())
        obj.Name = "山田太郎"
        Console.WriteLine(obj.ToString())

        '終了
        Console.ReadLine()
    End Sub

End Module



文法
 文法に難しいところはないのですが、○○ End を多用している点が気になる人が居るかと思います。○○ Endで括るプログラムはコードブロックを表わしています。つまり、データにアクセスするコード群を指定しているのです。コードブロックがわかれば、プロパティのプログラムを問題なく読み書きできます。

解説
 ほとんどのオブジェクトは何らかのデータを持っています。そしてプログラミングでは、データを読み書きするにはプログラムが必要です。それで、プロパティの文法は、データの名前と型、読み取りと書き取りのコードの塊であるコードブロックを指定する形式になっています。単純にデータを読み書きするだけならば、変数に値を設定すればいいという事になりますが、それだけではプログラミングは成り立ちません。データの整合性を常に保ち、データを正しいものに維持する必要があります。
 データを整合性がある状態に保つには、ただ単に変数の値を変えるだけではなく、入力値をチェックするプログラムと、変数を加工して外部に渡す機能が必要になります。それに加えて、アクセスの範囲をチェックする必要があります。その2つの要請をかなえる形で表現したものがプロパティです。アクセスできる範囲をチェックするのは原始的なセキュリティ機能なので、もしかしたらより高度なセキュリティ機能を持つ、新しい文法が将来登場するかもしれません。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - イテレータ(反復子)

概要
 .NETに適したやり方で繰り返し処理を抽象化するオブジェクト作りたい場合、IEnumeratorインタフェースを実装します。そのIEnumeratorインタフェース実装の手間を省き、プログラムを読みやすくします。

使用に適した状況
 複数のインスタンスを管理するオブジェクトを実装したい場合。例えば、売上明細オブジェクトをもつ、売上オブジェクトなどが該当します。

サンプル

'---------------------------------------------

'反復子(イテレータ)

'---------------------------------------------
Imports System
Imports System.Collections.Generic

'指定した範囲の数値を保持するオブジェクト
Class Range
    Private first As Integer
    Private last As Integer

    Public Iterator Function GetEnumerator() As IEnumerator(Of Integer)
        For i As Integer = Me.first To Me.last
            If i = 100 Then
                Exit For '生成を終了する
            End If
            Yield i '値を生成して返す
        Next
    End Function

    Public Sub New(ByVal first As Integer, ByVal last As Integer)
        Me.first = first
        Me.last = last
    End Sub

End Class

Module Iterator

    Sub Main()

        '値が最後まで生成されて表示される
        Dim obj As Range = New Range(10, 20)
        For Each v As Integer In obj
            Console.Write("{0} ", v)
        Next
        Console.WriteLine()

        '空白だけ表示される
        obj = New Range(100, 300)
        For Each v As Integer In obj
            Console.Write("{0} ", v)
        Next
        Console.WriteLine()

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 「Yield 」ステートメントを使用します。Yield ステートメントの後ろには返す値を書きます。

解説
 .NET環境でプログラミングをするとき、IEnumeratorインタフェースを実装するオブジェクトを作ることが多々あります。何故ならば、.NETにおいて、IEnumeratorインタフェースは非常に重要なものだからです。IEnumeratorインタフェースを実装しておくと、LINQプログラミングでもそのオブジェクトを扱えるようになりますし、予め用意されているオブジェクトとも相性が良くなります。
 しかしながら、IEnumeratorインタフェースを実装するのは意外と面倒です。決まったパターンがあるのにもかかわらず、毎回同様のプログラムを書くのは面倒ですし、プログラムが長くなって本当に重要なプログラムが見えにくくなります。そういったことから、VBにはIEnumeratorインタフェースの実装をサポートするための文法が用意されています。
 ただし、文法が用意されているからと言って、どうなっているのかを知らなくてもよいという事はありません。一度は、IEnumeratorインタフェースを自分で実装してみましょう。実装がサポートされているかと言って、理解しなくてもよいという事はありません。理解することを前提としてイテレータが用意されていると考えるとよいでしょう。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - クエリ式

概要
 場所や形式に関係なく、データを取り扱います。

使用に適した状況
 データを扱う状況全てです。今のところは、データの読み出しに限定されていますが、いずれは、データの変更にも使用できるようになるでしょう。

サンプル

'------------------------------------------------------------

'クエリ式

'------------------------------------------------------------
Imports System
Imports System.Collections.Generic
Imports System.Linq

Class Member
    Public Property Count As Integer
    Public Property Name As String
    Public Sub New(ByVal id As Integer, ByVal name As String)
        Me.Count = id
        Me.Name = name
    End Sub
End Class

Module Sample

    Sub Main()

        'データを準備
        Dim list As List(Of Member) = New List(Of Member)() From {
            New Member(11, "A"),
            New Member(20, "B"),
            New Member(14, "C"),
            New Member(10, "D"),
            New Member(9, "E")
        }
        For Each m As Member In list
            Console.WriteLine("Count:{0}, Name:{1}", m.Count, m.Name)
        Next
        Console.WriteLine()

        'クエリ式を実行
        Console.WriteLine("購入数が0を超えるメンバーを名前の降順で表示します・・・")
        Dim result = From m In list
                Where m.Count > 10
                Order By m.Name Descending
                Select m.Name
        For Each m As String In result
            Console.WriteLine("Name:{0}", m)
        Next
        Console.WriteLine()

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 いろいろな書き方ができるSelect、Order By、Where 、Fromの四つの句を、1度に全て使用した例です。SQLとは違い、from句が最初に書かれている点に注意してください。SQLはFROM句の位置が、宣言型としては不適切だと指摘されていました。マイクロソフトはそれを解消したのでしょう。SQLに慣れていると違和感を覚えるでしょうが、宣言型としては正しい形式です。この形式だと、構文解析もやりやすく、思考の流れに沿っていると思います。
 今回は一目で概要がわかるようにしましたが、クエリ式はLINQプログラミングで使用します。LINQプログラミングは、奥が深いものなのでリファレンスでは入口しか紹介できませんでした。詳しくは今後書く予定の別の記事を参考にしてください。

解説
 情報システムにおいて、データは必須要素です。しかしながら、そのデータの位置もしくは、データの形式により、使用技術が違いました。例えば、データベースにある場合はSQL、XML形式のファイルにある場合はXQueryなど、データの内容は同じでも、様々な技術を覚え、書き分ける必要がありました。LINQはその問題を解決するべく作られて技術であり、クエリ式はLINQプログラミングをやりやすく行うための言語要素です。VBを使用すると、LINQプログラミングがやりやすくなります。
 LINQプログラミングと書くと、一般のプログラマーに関係がないように思う人が居るかもしれません。しかしながら、データを全く使用しない実務プログラミングはほぼありません。全ての人が関係のある、それこそループ構文ぐらい使用頻度が高いものです。
 なお、クエリ式のサポートにより、VBは宣言型プログラミングをするのが一般的になっています。このブログでは、敷居を低くするために極力避けていました。ですが、現在のVBプログラミングは、クエリ式を使った宣言型プログラミングをするのが普通です。どの言語でもループなどの文法は必須です。それと同様に、VBを使用するならば、クエリ式は必須だと考えるとよいでしょう。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 変数名の省略

概要
 変数名を省略してプログラムを読みやすくします。

使用に適した状況
 同じ変数に対して、1連の処理があり、なおかつメソッドとして纏めるのが不適切な場合。また、1連のプログラムの主役(注目するべきオブジェクト)を読み手に示したい場合も適しています。

サンプル

'---------------------------------------------

'Withステートメントによる変数名の省略

'---------------------------------------------
Imports System

Class Customer
    Public Property ID As Integer
    Public Property Name As String
End Class

Class Product
    Public Property Name As String
    Public Property Price As Integer
End Class

Module Sample

    Sub Main()

        '変数名を省略できる
        Dim target As Customer = New Customer()
        With target
            .ID = 10
            .Name = "山田太郎"
        End With

        '入れ子構造も可能
        With target
            Dim soldGoods As Product = New Product()
            soldGoods.Name = "ポテチ"
            With soldGoods
                Console.WriteLine("どっちが表示される?:{0}", .Name)
                '外側の変数名を省略できない
                'Console.WriteLine("購入者:{0}", .ID)
            End With
        End With

        '終了
        Console.ReadLine()
    End Sub

End Module


文法
 Withキーワードと省略したい変数名を指定し、End Withで終了します。省略した変数名は「 . 」(ピリオド記号)で指定します。入れ子構造にすることもできます。しかしながら、入れ子構造にした場合、予期せぬ動作をする恐れがあります。入れ子構造は慎重に使用するべきです。

解説
 同じ変数に対して、複数のプロパティの値を設定したいときが多々あります。また、1つのオブジェクトが主となるプログラムが続く状況があります。そうした状況で、Withステートメントを使用すると、読み手に主となるオブジェクトを知らせることができます
 ただし、変数名を打つのが面倒だという理由で多用してはなりません。逆にプログラムが読みにくくなる恐れがあります。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 初期化子

概要
 オブジェクトの初期化と、プロパティ値の設定を簡単に記述するための文法です。これにより、利便性のためにコンストラクタを用意しなくてもよいようになります。

使用に適した状況
 利便性や可読性のためだけに、余計なコンストラクタが増えて困っている。もしくは、1つも無駄なコンストラクタを定義したくないときに使用します。オブジェクト指向設計の観点から言って、そういった本質とは関係のないコンストラクタは、実装するべきではないので常に使えると言ってもよいと思います。

サンプル

'---------------------------------------------

'初期化子

'---------------------------------------------
Imports System.Collections.Generic

Class Member
    Public Property ID As Integer
    Public Property Name As String

    Public Overrides Function ToString() As String
        Return String.Format(
            "ID:{0}, Name:{1}", Me.ID, Me.Name)
    End Function
End Class

Module Initializers

    Sub Main()
        '名前がある通常の型を初期化
        Dim obj As Member = New Member With {.ID = 10, .Name = "山田太郎"}
        Dim obj1 = New Member With {.ID = 20, .Name = "案山子"}

        '匿名型の初期化
        Dim obj2 = New With {.ID = 200, .Name = "山田花子"}

        'コレクションの初期化
        Console.WriteLine("コレクション初期化子を使用します")
        Dim memberList As List(Of Member) = New List(Of Member) From
        {
            New Member With {.ID = 10, .Name = "山田太郎"},
            New Member With {.ID = 20, .Name = "山田花子"}
        }
        For Each e As Member In memberList
            Console.WriteLine(e.ToString())
        Next
        Console.WriteLine()

        '終了
        Console.WriteLine("終了")
        Console.ReadLine()

    End Sub

End Module


文法
 New Withと{}を使用して、その中で「.プロパティ名 = 値 」と書きます。細かく分類すると、単体のオブジェクト初期化子と、複数を指定したい場合の>コレクション初期化子があります。しかし、2つの初期化子には、共通したパターンの書き方があるので困らないと思います。違いは、コレクション初期化子にはFromキーワードを使用する点です。
 なおNew Withキーワードは、New演算子とWithステートメントと併用していると覚えると良いでしょう。VBをよく使っている人にとって、Withステートメントはなじみ深く、プロパティ名の前のドットを忘れないようにするのに効果的だと思います。

解説
 オブジェクトを定義しているとき、オブジェクトを初期化してから、プロパティに値を設定するのが面倒かつ美しくありません。本当に表現したい事が見えにくくなります
 それでプログラマーは、初期化用のコンストラクタを用意します。こうすることにより、一度に初期化とプロパティの設定を行うことが可能となります。しかしながら、設計面から考えると、余計なコンストラクタを用意することは望ましくありません。何故ならば、本来は実装する必要がない、設計とは無関係なコードが入り込むからです。さらに、プロパティの組み合わせは莫大な数になりえます。その両方を解決する文法が初期化子です。初期化子があれば、実装者は無駄なコンストラクタを定義する必要がなくなり、なおかつオブジェクトの使用者も簡潔に記述できます。糖衣文だといわれることもありますが、設計と実装面を考えた非常に良い文法だと思います。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 匿名型

概要
 メソッド内でのみ使用する、データしか持たない単純な型を簡潔な記述で生成します。

使用に適した状況
 特定のメソッド内で、一時的に作成する必要がある、データしか持たない単純な型が必要な場合。

サンプル

'------------------------------------------------------------

'匿名型

'------------------------------------------------------------
Imports System
Module AnonymousTypes

    Sub Main()
        '型を省略し、New Withを使用すると
        'コンパイラが自動的に型を作成する
        Dim obj = New With {.Name = "山田太郎", .ID = 10}
        Dim obj1 = New With {.Name = "山田花子", .ID = 20}
        Dim obj2 = New With {.Name = "山田太郎", .ID = 10}

        '匿名型のインスタンスを変更可能
        obj.ID = 20
        obj.Name = "山田次郎"
        obj.ID = 10
        obj.Name = "山田太郎"

        '匿名型のインスタンスは自身のみ等価
        Console.WriteLine(
            "山田太郎(ID:10)と山田花子(ID:20)の等価性:{0}",
             obj.Equals(obj1))
        Console.WriteLine(
            "山田太郎(ID:10)と同じインスタンスの等価性:{0}",
            obj.Equals(obj))
        Console.WriteLine(
            "山田太郎(ID:10)と内容が同じ別のインスタンスの等価性:{0}",
            obj.Equals(obj2))
        Console.WriteLine()

        'キーを指定すると、ハッシュ値と等価に使用できる。
        Console.WriteLine("キーを指定して等価性を判定できるようにします・・・")
        Dim obj3 = New With {.Name = "山田太郎", Key .ID = 10}
        Console.WriteLine(
            "内容が同じインスタンスを比較(Keyの指定なし):{0}",
            obj.Equals(obj3)) 'Keyプロパティの指定がないのでFalse
        Dim obj4 = New With {.Name = "山田太郎", Key .ID = 10}
        Console.WriteLine(
            "内容が同じインスタンスを比較(Keyの指定あり):{0}",
            obj3.Equals(obj4))
        Dim obj5 = New With {Key .Name = "山田太郎", Key .ID = 10}
        Console.WriteLine(
            "内容は同じだが、Keyで指定するプロパティの値が違うインスタンスを比較:{0}",
            obj3.Equals(obj5)) 'Keyに指定するプロパティが違うのでFalse
        'Console.WriteLine(obj3 = obj4) '等価演算子が定義されていないのでエラー
        Console.WriteLine()

        'キー指定したプロパティは変更できない
        'obj3.ID = 100
        obj3.Name = "山田次郎"

        '位置でも指定できる
        '※等価性の判定に注意
        Dim name As String = "山田太郎"
        Dim id As Integer = 15
        Dim obj6 = New With {name, id}
        'Console.WriteLine( "{0}と{1}は同じ? {2}",
        '    obj, obj5, obj == obj5 )

        '終了
        Console.ReadLine()

    End Sub

End Module

文法
 匿名型は、New Withキーワードと{}を使用して指定します。見た目は、型推論(ローカル型の推論)と初期化子を組み合わせたものです。しかし、プロパティの値を位置で指定できるところが違います。メソッドは指定できず、戻り値の型を匿名型にすることはできません。他にも細かい制限はありますが、一時的に使用するデータとして考えれば理解しやすいと思います。
 通常のクラスと比べると制限は厳しいものの、変更の有無を柔軟に指定できます。Keyキーワードを指定すると、そのプロパティは不変となり、等価判定に有効に働きます。Equalsメソッドやプロパティのコードまでコンパイラが自動的に生成してくれます。

解説
 使用方法を詳しく説明します。他の方法を考えると、プライベート型を作成する方法もあります。しかし、特定のメソッド内でのみ使用する単純なオブジェクトを型として定義すると、複数のメソッドで使用する型なのか、特定のメソッド内のみ使用する型なのかが分かりません。その判別は一見どうでもよいことですが、複数のメンバーで大量のコードを保守する必要がある実務において、余計な型を定義すると混乱を生みます。特定のメソッド内でのみ使用しない単純なオブジェクトは、匿名型として扱うとよいでしょう。
 なお、匿名オブジェクトには、データとして考えるとよいと分かりやすいと思います。厳しい制限が気になるかもしれませんが、一時データとしてみると極めて自然な制限だと思います。

テーマ : プログラミング
ジャンル : コンピュータ

VB文法リファレンス - 拡張メソッド

概要
 継承を使わず、既存のオブジェクトに振る舞い(メソッド)を追加します。言い換えると、既存オブジェクトを拡張しているといえます。

使用に適した状況
 無暗にオブジェクトの数を増やさず、既存オブジェクトに対して、特定の問題領域(ドメイン)内のみ有効な振る舞いを追加したい。もしくは、既存の型が継承不可になっているとき、どうしても型の振る舞いを増やしたい。ただし、継承不可のオブジェクトの振る舞いを追加したい場合は、合成オブジェクトやデザインパターンを使用したほうが良いと思います。

サンプル

'----------------------------------------------------
' 
'  拡張メソッド
'  
'-----------------------------------------------------
Imports System
Imports System.Runtime.CompilerServices '拡張メソッドを定義する為に必要

Namespace Data

    Class Customer

        Private _id As Integer
        Public ReadOnly Property ID As Integer
            Get
                Return Me._id
            End Get
        End Property

        Private _name As String
        Public ReadOnly Property Name As String
            Get
                Return Me._name
            End Get
        End Property

        Public Sub New(ByVal id As Integer, ByVal name As String)
            Me._id = ID
            Me._name = Name
        End Sub

    End Class
End Namespace

Namespace Service

    '拡張メソッドはモジュールでしか定義できない
    Module Sales

        '拡張メソッド
        '属性を指定する
        <Extension()>
        Public Function GetSpecialPrice(ByVal c As Data.Customer, ByVal basePrice As Integer) As Double
            Return basePrice * 0.8
        End Function

        Public Sub Main()
            Dim obj As Data.Customer = New Data.Customer(100, "山田商事")
            Dim price As Integer = 100
            Console.WriteLine(
                "{0}様のご購入金額は{1}万円( 基本価格{2}万円 )です。",
                obj.Name, obj.GetSpecialPrice(price), price)
            Console.ReadLine()
        End Sub

    End Module
End Namespace


文法
 モジュールを用意し、Extension属性をつけてメソッドを宣言します。します。この宣言した関数が付け加えられる型(拡張される型)は、最初に宣言した引数(パラメーター)です。
 これは文法の条件ではないのですが、拡張メソッドの使用を意識的に選択できるようにするために、名前空間との併用が望ましいと思われます。プログラマーが意識することなく拡張メソッドが適用されてしまうと、自分が定義した覚えのないメソッドがあることから混乱が生じる恐れがあります。メソッドのオーバーロードと絡むと、コンパイラが選択するメソッドのルールが複雑化します。

解説
 例えば、顧客データの様なオブジェクトは、各部門別が違う用途に使用します。この様な使いまわすオブジェクトを表現するために、子オブジェクトを定義する方法を採ると、オブジェクトの数が無暗に増え、保守性低下などの悪影響を及ぼします。また結果として、システムの拡張が妨げられます。
 この現象を避ける方法のうちの1つが拡張メソッドです。上手く拡張メソッドを使用すれば、効果が薄い子オブジェクトの増殖を減らせます。ただし、あまりにも特殊な動作をするオブジェクトを定義したい場合は、素直に継承を使用したほうが良いでしょう。
 拡張メソッドのお手本はLINQです。LINQで使用されているオブジェクトを調べると、拡張メソッドの上手な使い方が学べます。

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター