このページでは、プロシージャを操作するときに発生する可能性がある一般的な問題の一覧を示します。
関数プロシージャから配列型を返す
Function プロシージャが配列データ型を返す場合、Function名を使用して配列の要素に値を格納することはできません。 これを行おうとすると、コンパイラはそれを Functionの呼び出しとして解釈します。 次の例では、コンパイラ エラーが生成されます。
Function AllOnes(n As Integer) As Integer()
For i As Integer = 1 To n - 1
' The following statement generates a COMPILER ERROR.
AllOnes(i) = 1
Next
' The following statement generates a COMPILER ERROR.
Return AllOnes()
End Function
ステートメントAllOnes(i) = 1間違ったデータ型 (Integer配列ではなくスカラー Integer) の引数を使用してAllOnesを呼び出すように見えるため、コンパイラ エラーが生成されます。 ステートメント Return AllOnes() は、引数なしで AllOnes を呼び出しているように見えるため、コンパイラ エラーを生成します。
正しいアプローチ: 返される配列の要素を変更できるようにするには、内部配列をローカル変数として定義します。 次の例では、エラーなしでコンパイルされます。
Function AllOnes(n As Integer) As Integer()
Dim iArray(n - 1) As Integer
For i = 0 To n - 1
iArray(i) = 1
Next
Return iArray
End Function
プロシージャ呼び出しによって変更されない引数
プロシージャが呼び出し元コードの引数の基になるプログラミング要素を変更できるようにする場合は、参照渡しで渡す必要があります。 ただし、プロシージャは、値渡しした場合でも、参照型引数の要素にアクセスできます。
基になる変数。 プロシージャが基になる変数要素自体の値を置き換えるには、プロシージャでパラメーター ByRef を宣言する必要があります。 また、呼び出し元のコードでは、引数をかっこで囲む必要はありません。これは、
ByRef渡しメカニズムをオーバーライドするためです。参照型の要素。 パラメーター ByVal を宣言した場合、プロシージャは基になる変数要素自体を変更できません。 ただし、引数が参照型の場合、プロシージャは、変数の値を置き換えることはできませんが、それが指すオブジェクトのメンバーを変更できます。 たとえば、引数が配列変数の場合、プロシージャは新しい配列を割り当てることはできませんが、1 つ以上の要素を変更できます。 変更された要素は、呼び出し元のコードの基になる配列変数に反映されます。
次の例では、配列変数を値で受け取り、その要素を操作する 2 つのプロシージャを定義します。 プロシージャ increase は、各要素に 1 つを追加するだけです。 プロシージャ replace は、パラメーター a() に新しい配列を割り当て、各要素に 1 つ追加します。 ただし、 a() は ByVal宣言されているため、再割り当ては呼び出し元のコードの基になる配列変数には影響しません。
Public Sub increase(ByVal a() As Long)
For j As Integer = 0 To UBound(a)
a(j) = a(j) + 1
Next j
End Sub
Public Sub replace(ByVal a() As Long)
Dim k() As Long = {100, 200, 300}
a = k
For j As Integer = 0 To UBound(a)
a(j) = a(j) + 1
Next j
End Sub
次の例では、 increase と replaceを呼び出します。
Dim n() As Long = {10, 20, 30, 40}
Call increase(n)
MsgBox("After increase(n): " & CStr(n(0)) & ", " &
CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
Call replace(n)
MsgBox("After replace(n): " & CStr(n(0)) & ", " &
CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
最初の MsgBox 呼び出しには、"After increase(n): 11, 21, 31, 41" と表示されます。
nは参照型であるため、increaseByVal渡された場合でもメンバーを変更できます。
2 番目の MsgBox 呼び出しには、"After replace(n): 11, 21, 31, 41" と表示されます。
nはByVal渡されるため、replaceは新しい配列を割り当てることで変数nを変更することはできません。
replace新しい配列インスタンスkを作成し、ローカル変数aに割り当てると、呼び出し元のコードによって渡されたnへの参照が失われます。
aのメンバーをインクリメントすると、ローカル配列kのみが影響を受けます。
正しいアプローチ: 基になる変数要素自体を変更できるようにするには、それを参照渡しします。 次の例は、呼び出し元のコードで配列を別の配列に置き換えることができる replace の宣言の変更を示しています。
Public Sub replace(ByRef a() As Long)
オーバーロードを定義できません
プロシージャのオーバーロードされたバージョンを定義する場合は、同じ名前と異なるシグネチャを使用する必要があります。 コンパイラが同じシグネチャを持つオーバーロードと宣言を区別できない場合は、エラーが生成されます。
プロシージャの シグネチャ は、プロシージャ名とパラメーター リストによって決まります。 各オーバーロードは、他のすべてのオーバーロードと同じ名前を持つ必要がありますが、シグネチャの他のコンポーネントの少なくとも 1 つでは、それらすべてとは異なる必要があります。 詳細については、「 プロシージャのオーバーロード」を参照してください。
次の項目は、パラメーター リストに関連していても、プロシージャのシグネチャのコンポーネントではありません。
- プロシージャ修飾子キーワード (
Public、Shared、Staticなど)。 - パラメーター名。
- パラメーター修飾子キーワード (
ByRefやOptionalなど)。 - 戻り値のデータ型 (変換演算子を除く)。
上記の 1 つ以上の項目のみを変更してプロシージャをオーバーロードすることはできません。
正しいアプローチ: プロシージャのオーバーロードを定義できるようにするには、シグネチャを変更する必要があります。 同じ名前を使用する必要があるため、パラメーターの数、順序、またはデータ型を変更する必要があります。 ジェネリック プロシージャでは、型パラメーターの数を変更できます。 変換演算子 (CType 演算子) では、戻り値の型を変更できます。
Optional 引数と ParamArray 引数を使用したオーバーロードの解決
1 つ以上の 省略可能 なパラメーターまたは ParamArray パラメーターを使用してプロシージャをオーバーロードする場合は、 暗黙的なオーバーロードの複製を回避する必要があります。 詳細については、「 プロシージャのオーバーロードに関する考慮事項」を参照してください。
オーバーロードされたプロシージャの間違ったバージョンの呼び出し
プロシージャに複数のオーバーロードされたバージョンがある場合は、すべてのパラメーター リストを理解し、Visual Basic でオーバーロード間の呼び出しがどのように解決されるかを理解する必要があります。 それ以外の場合は、目的のオーバーロード以外のオーバーロードを呼び出す可能性があります。
呼び出すオーバーロードを決定したら、次の規則に注意してください。
- 正しい数の引数を正しい順序で指定します。
- 理想的には、引数には、対応するパラメーターとまったく同じデータ型が必要です。 いずれの場合も、各引数のデータ型は、対応するパラメーターのデータ型に拡大する必要があります。 これは、 Option Strict ステートメント が
Offに設定されている場合でも当てはまります。 オーバーロードで引数リストからの縮小変換が必要な場合、そのオーバーロードは呼び出しの対象になりません。 - 拡大を必要とする引数を指定する場合は、対応するパラメーターのデータ型にできるだけ近いデータ型にします。 2 つ以上のオーバーロードが引数データ型を受け入れる場合、コンパイラは、拡大の最小量を呼び出すオーバーロードの呼び出しを解決します。
引数を準備するときに CType 関数 変換キーワードを使用すると、データ型の不一致の可能性を減らすことができます。
オーバーロード解決エラー
オーバーロードされたプロシージャを呼び出すと、コンパイラはオーバーロードの 1 つを除くすべてを排除しようとします。 成功すると、そのオーバーロードの呼び出しが解決されます。 すべてのオーバーロードが削除された場合、または対象となるオーバーロードを 1 つの候補に減らすことができない場合は、エラーが生成されます。
次の例は、オーバーロード解決プロセスを示しています。
Overloads Sub z(ByVal x As Byte, ByVal y As Double)
End Sub
Overloads Sub z(ByVal x As Short, ByVal y As Single)
End Sub
Overloads Sub z(ByVal x As Integer, ByVal y As Single)
End Sub
Dim r, s As Short
Call z(r, s)
Dim p As Byte, q As Short
' The following statement causes an overload resolution error.
Call z(p, q)
最初の呼び出しでは、最初の引数 (Short) の型が対応するパラメーター (Byte) の型に絞り込まれるため、コンパイラは最初のオーバーロードを排除します。 2 番目のオーバーロード (Short および Single) の各引数の型が、3 番目のオーバーロード (Integer および Single) 内の対応する型に拡大されるため、3 番目のオーバーロードは削除されます。 2 番目のオーバーロードでは、より少ない拡大が必要になるため、コンパイラは呼び出しに使用します。
2 番目の呼び出しでは、コンパイラは縮小に基づいてオーバーロードを排除できません。 引数型の拡大が少ない状態で 2 番目のオーバーロードを呼び出すことができるため、最初の呼び出しと同じ理由で 3 番目のオーバーロードが削除されます。 ただし、コンパイラは最初のオーバーロードと 2 番目のオーバーロードの間で解決できません。 それぞれには、もう一方の型 (ShortにByte、DoubleにSingle) に拡大する 1 つの定義済みのパラメーター型があります。 したがって、コンパイラはオーバーロード解決エラーを生成します。
正しいアプローチ: あいまいさなしでオーバーロードされたプロシージャを呼び出すことができるようにするには、 CType 関数 を使用して、引数のデータ型をパラメーター型と照合します。 次の例は、2 番目のオーバーロードに解決を強制する z の呼び出しを示しています。
Call z(CType(p, Short), CType(q, Single))
Optional 引数と ParamArray 引数を使用したオーバーロードの解決
プロシージャの 2 つのオーバーロードに同じシグネチャがある場合、最後のパラメーターが一方で Optional と宣言され、もう一方の パラメーターで ParamArray が宣言されている点が異なります。コンパイラは、最も近い一致に従ってそのプロシージャの呼び出しを解決します。 詳細については、「オーバーロードの 解決」を参照してください。
こちらも参照ください
.NET