.NET VB Subプロシージャ、Functionプロシージャの基本
プロシージャの基本的な使用方法について解説しています。また、引数の渡し方(ByVal、ByRef)、任意位置で処理を抜ける方法(Exit Sub、Return)、引数に配列の渡し方、オーバーロード、Optional演算子による引数にデフォルト値を設定する方法、引数に仮引数名(:=)を使用した値の渡し方、引数にパラメーターリスト(ParamArray演算子)を使用する方法についても解説しています。
プロシージャ(Sub・Function)使用方法
VB(VisualBasic)では、SubプロシージャとFunctionプロシージャがある。SubプロシージャとFunctionプロシージャの主な違いは、呼び出し元に値を返せるか返せないかです。
以下によくある使い方の図を記載します。
Subプロシージャ定義
Subプロシージャは、SubとEnd Subの間に定義し、その中に実行したい処理を定義する。引数は複数定義することができ、カンマ(,)で区切って定義する。この引数のことを仮引数と言う。また、Subプロシージャは、値を返すことができないので、呼び出し元に値を返す必要がない処理は、Subプロシージャを使用する。
呼び出し方については、モジュール名.プロシージャ名とカッコ内に引数をセットする。モジュール名名は、省略できるが他のモジュールで同名のプロシージャ名があった場合は、どちらのプロシージャ名を示しているか曖昧なため、基本的にはモジュール名を指定したほうがよい。
呼び出し方
モジュール名.プロシージャ名(実引数,...)
プロシージャ名(実引数...) 'モジュール名の省略
構文
アクセス属性 Sub プロシージャ名(引数の渡し方 仮引数名 As データ型,...)
実行する処理
・
・
End Sub
サンプル
'コンソール出力時に現在の日時を出力テキストに付加する。
Public Sub OutConsole(ByVal str As String)
Console.WriteLine(Now & ":" & str)
End Sub
'複数の仮引数
Public Sub OutConsole(ByVal number As Integer, ByVal str As String)
Console.WriteLine("[" & number & "]" & Now & ":" & str)
End Sub
Function(関数)プロシージャ定義
Functionプロシージャは、基本的にはSubと同じである。ただし、関数であるため戻り値のデータ型を定義する必要がある。また、関数内に必ずReturnで戻り値を定義する必要がある。
呼び出し方
格納する変数 = モジュール名.プロシージャ名(実引数,...)
格納する変数 = プロシージャ名(実引数...) 'モジュール名の省略
構文
アクセス演算子 Function プロシージャ名(引数の渡し方 仮引数名 As データ型,...)As 戻り値のデータ型
ステートメント
・
・
プロシージャ名 = 値 もしくは、Return 値
End Function
サンプル
Private taxRate As Double = 0.08
Private Function GetTax(ByVal price As Integer)
Return price * (taxRate)
End Function
プロシージャの定義位置
プロシージャの定義位置は、プロシージャの呼び出しより前でも後でもよい。
Exitを使用し任意位置で処理を抜ける。
Exit Sub、Exit Functionステートメントを使用することにより、任意の位置で処理を抜けることができます。
サンプル:Exit Sub
Module Program
Sub Main(args As String())
OutConsole(1, "VB .NET")
OutConsole(2, "マイクロソフト社が開発した Visual Basic .NETを使って誰でも簡単にできるプログラミングをしてみよう")
End Sub
Public Sub OutConsole(ByVal number As Integer, ByVal str As String)
If str.Length <= 50 Then
Console.WriteLine("[" & number & "]" & Now & ":" & str)
Else
Exit Sub
End If
End Sub
End Module
サンプル:Exit Function
'消費税込みの金額を計算するプロシージャ
Private Function GetSumPrice(ByVal price As Integer, ByVal tax As Integer) As Integer
If price = 0 Then
'priceが0円の場合、計算せずExitで処理を抜ける。
GetSumPrice = 0
Exit Function
End If
GetSumPrice = price * (tax / 100)
Exit Function
End Function
引数の渡し方
SubプロシージャやFunctrionプロシージャの仮引数に値を渡すとき、値渡し(ByVal)と参照渡し(ByRef)の2種類があります。
VB6.0のデフォルトの引数の引渡しはByRefであるが、VB .NETのデフォルトの引数渡しはByValである。
値による呼び出し(ByVal)
値渡しは、元の値がコピーされプロシージャの仮引数に渡されます。仮引数の宣言時にByValキーワードを使う。値渡しの場合は、渡された値をプロシージャ内で変更しても、元の値は変更されないので独立性が担保される。
サンプル
Private Function GetTax(ByVal price As Integer)
Return price * (taxRate)
End Function
参照渡し(ByRef)
参照渡しは、元の値がどこにあるかという情報(値のアドレス)をプロシージャに渡します。呼び出した側と呼び出されたプロシージャの変数は、同じ変数となります。つまり、プロシージャ内で変数の値を変更した場合、呼び出した側の変数内の値が変更されたことになる。
サンプル
Private Sub GetTax(ByRef price As Integer)
price = price * (taxRate)
End Sub
複数の変数及び値を呼び出し元に返せる。
ByRefの一番の利点は、Functrionでは1つの値もしくは、変数しか返せないが、仮引数を複数定義することで、引数経由で複数の値・変数を呼び出し元に返すことができる。
ただし、この方法はあまり好ましくはありません。なぜなら、変数がいつどこで、どのプロシージャで変更されるかスパゲッティのように絡み合うリスクがあるため、なるべくはクラスのアクセサメソッドを検討するほうがよいだろう。
値渡しと参照渡しどっちを使う?
ケースバイケースではあるが、基本的に値渡し(ByVal)である。中規模から大規模システムや基幹系システムとなると膨大なソースコードになる。その場合、不具合の削減や特定を用意にするためには、変数やプロシージャのスコープ(有効範囲)は、なるべく狭くするほうがよい。狭いということは、影響範囲を小さくすることができるので、調査や修正の労力が最小限になることが多い。
PrivateとPublic
スコープをPrivateの場合は、そのモジュール内の調査で済むが、Publicの場合は、調査対象がプロジェクト全体となる。
引数に配列を渡す。
仮引数に配列を渡すことができる。配列はByRefによる参照渡しで行う。
1次元配列
サンプル
Dim price(10) As Integer
PriceSum(price)
'サブプロシージャ
Pvivate Sub PriceSum(ByRef price() As Integer)
price(0) = 1000
End Sub
2次元配列
1次元配列と同じであるが、仮引数の宣言はprice(,)のようにカンマで区切る必要がある。
サンプル
Dim price(2,10) As Integer
PriceSum(price)
'サブプロシージャ
Pvivate Sub PriceSum(ByRef price(,) As Integer)
price(0) = 1000
End Sub
Optional演算子:引数の省略
Optional演算子をSubプロシージャやFunctrionプロシージャの引数に指定すると、呼び出すときに引数を省略することができる。また、省略時の初期値を指定できる。
Optionalキーワードを指定した引数以降、すべてOptional指定をしなければならない。
サンプル
Sub Main(args As String())
'省略した場合
OutConsole(name:="鈴木 次郎", age:=35, gender:="男性")
End Sub
Public Sub OutConsole(ByVal name As String, ByVal age As Integer, Optional ByVal gender As String = "")
Console.WriteLine("名前:" & name)
Console.WriteLine("年齢:" & age)
Console.WriteLine("性別:" & gender)
End Sub
'Optionalを複数仮引数に指定した場合
Public Sub OutConsole(ByVal name As String, ByVal age As Integer, Optional ByVal gender As String = "", Optional ByVal hireDate As String = "")
Console.WriteLine("名前:" & name)
Console.WriteLine("年齢:" & age)
Console.WriteLine("性別:" & gender)
Console.WriteLine("入社日:" & hireDate)
End Sub
'NG例
Public Sub OutConsole(ByVal name As String, ByVal age As Integer, Optional ByVal gender As String = "", ByVal hireDate As String)
Console.WriteLine("名前:" & name)
Console.WriteLine("年齢:" & age)
Console.WriteLine("性別:" & gender)
Console.WriteLine("入社日:" & hireDate)
End Sub
名前付き引数
プロシージャを呼び出すときに、指定する仮引数に「仮引数名:=値」を指定することで、引数の順序に関係なく値が渡される。引数が多い場合や省略可能(Optional)引数を持つプロシージャに有効的である。
サンプル
Sub Main(args As String())
'仮引数に:=を使用した場合
OutConsole(name:="田中 太郎", age:=21, gender:="男性", hireDate:="2020/04/01")
'仮引数を順不同で配置した場合
OutConsole(gender:="女性", age:=20, name:="佐々木 花子", hireDate:="2021/04/01")
'一部省略した場合
OutConsole(name:="鈴木 次郎", age:=35, hireDate:="2020/04/01")
End Sub
Public Sub OutConsole(ByVal name As String, ByVal age As Integer, Optional ByVal gender As String = "", Optional ByVal hireDate As String = "")
Console.WriteLine("名前:" & name)
Console.WriteLine("年齢:" & age)
Console.WriteLine("性別:" & gender)
Console.WriteLine("入社日:" & hireDate)
End Sub
不定個数の引数:ParamArray演算子
プロシージャやメソッドに引数を渡すとき、実際にプログラムを実行するまで引数の数が決まらない場合がある。その場合は、可変長のパラメーターリストのParamArray演算子を使用することで、不定個数のデータを受け取ることができる。
呼び出し側の実引数には、配列を指定することもできます。
サンプル
'プロシージャの呼び出し側
Dim nameList() As String = {"四郎"}
'異なるパラメーターを実引数にセットしプロシージャを呼び出す
OutputShowGroupList("A", "花子", "太郎", "一郎", "次郎")
OutputShowGroupList("B", "三郎", "梅子")
OutputShowGroupList("C", nameList) 'パラメーターに配列を指定する。
'サブプロシージャ
Private Sub OutputShowGroupList(ByVal strGroup As String, ByVal ParamArray nameLt() As String)
For i As Integer = 0 To nameLt.Length() -1
Console.WriteLine("nameLt配列(" & i & ")" & nameLt(i))
Next i
End Sub
オーバーロード
オーバーロードは、同じ名前で異なるプロシージャやメソッドを定義することができる。プロシージャやメソッドを呼び出し時に引数の違いで判別されている。オーバーロードは、引数の数、引数の順序、引数のデータ型の違いにより判別できる。
以下の要素はオーバーロードできない。
Public、Shared、Staticなどのアクセス属性 |
引数の名前 |
ByRef、ByVal、Optionalなどの引数修飾子 |
戻り値のデータ型 |
サンプル
Private Function OutputShowGroupList(ByVal strGroup As String) As Integer
Return 1
End Function
'仮引数が複数の場合
Private Function OutputShowGroupList(ByVal strGroup1 As String, ByVal strGroup2 As String) As Integer
Return 1
End Function
'仮引数の型が異なる場合
Private Function OutputShowGroupList(ByVal strGroup1 As String, ByVal strGroup2 As Integer) As Integer
Return 1
End Function
'NG 仮引数の変数名の順番が異なる場合
Private Function OutputShowGroupList(ByVal strGroup2 As String, ByVal strGroup1 As Integer) As Integer
Return 1
End Function
'NG 関数の戻り値のデータ型が異なる場合
Private Function OutputShowGroupList(ByVal strGroup1 As String, ByVal strGroup2 As Integer) As String
Return 1
End Function
'NG 引数の渡し方が異なる場合
Private Function OutputShowGroupList(ByRef strGroup1 As String, ByRef strGroup2 As Integer) As Integer
Return 1
End Function
'NG アクセス属性が異なる場合
Public Function OutputShowGroupList(ByRef strGroup1 As String, ByRef strGroup2 As Integer) As Integer
Return 1
End Function
上記のNG以外は、プロシージャ名が同じでも異なるプロシージャとして扱われる。
スコープ
プロシージャは、アクセスできる範囲を指定することができます。
アクセス属性(利用可能な範囲)
プロシージャは、アクセスできる範囲を指定することができる。アクセシビリティとも言う。
アクセス属性
アクセス属性 | 内容 |
---|---|
Pvivate | 同一のモジュール(クラス・モジュール・フォーム)内でのみ利用できる。 |
Friend | 同一のプロジェクト内で利用できる。 |
Public | すべてのモジュール及び他のプロジェクトからの利用できる。 |
Protected | プロシージャが定義されているクラスと、継承先のメソッドから呼び出すことが可能である。 |
ProtectedFriend | プロシージャが定義されているクラス、サブクラス、または同じプロジェクトの 他のプロシージャからアクセスすることが可能である。 |