Generic Procedures in Visual Basic

A generic procedure, also called a generic method, is a procedure defined with at least one type parameter. This allows the calling code to tailor the data types to its requirements each time it calls the procedure.

A procedure is not generic simply by virtue of being defined inside a generic class or a generic structure. To be generic, the procedure must take at least one type parameter, in addition to any normal parameters it might take. A generic class or structure can contain nongeneric procedures, and a nongeneric class, structure, or module can contain generic procedures.

A generic procedure can use its type parameters in its normal parameter list, in its return type if it has one, and in its procedure code.

Type Inference

You can call a generic procedure without supplying any type arguments at all. If you call it this way, the compiler attempts to determine the appropriate data types to pass to the procedure's type arguments. This is called type inference. The following code shows a call in which the compiler infers that it should pass type String to the type parameter t.

Public Sub testSub(Of t)(ByVal arg As t)
End Sub
Public Sub callTestSub()
    testSub("Use this string")
End Sub

If the compiler cannot infer the type arguments from the context of your call, it reports an error. One possible cause of such an error is an array rank mismatch. For example, suppose you define a normal parameter as an array of a type parameter. If you call the generic procedure supplying an array of a different rank (number of dimensions), the mismatch causes type inference to fail. The following code shows a call in which a two-dimensional array is passed to a procedure that expects a one-dimensional array.

Public Sub demoSub(Of t)(ByVal arg() As t)
End Sub

Public Sub callDemoSub()
    Dim twoDimensions(,) As Integer
End Sub

You can invoke type inference only by omitting all the type arguments. If you supply one type argument, you must supply them all.

Type inference is supported only for generic procedures. You cannot invoke type inference on generic classes, structures, interfaces, or delegates.



The following example defines a generic Function procedure to find a particular element in an array. It defines one type parameter and uses it to construct the two parameters in the parameter list.


Public Function findElement(Of T As IComparable) (
        ByVal searchArray As T(), ByVal searchValue As T) As Integer

    If searchArray.GetLength(0) > 0 Then
        For i As Integer = 0 To searchArray.GetUpperBound(0)
            If searchArray(i).CompareTo(searchValue) = 0 Then Return i
        Next i
    End If

    Return -1
End Function


The preceding example requires the ability to compare searchValue against each element of searchArray. To guarantee this ability, it constrains the type parameter T to implement the IComparable<T> interface. The code uses the CompareTo method instead of the = operator, because there is no guarantee that a type argument supplied for T supports the = operator.

You can test the findElement procedure with the following code.

Public Sub tryFindElement()
    Dim stringArray() As String = {"abc", "def", "xyz"}
    Dim stringSearch As String = "abc"
    Dim integerArray() As Integer = {7, 8, 9}
    Dim integerSearch As Integer = 8
    Dim dateArray() As Date = {#4/17/1969#, #9/20/1998#, #5/31/2004#}
    Dim dateSearch As Date = Microsoft.VisualBasic.DateAndTime.Today
    MsgBox(CStr(findElement(Of String)(stringArray, stringSearch)))
    MsgBox(CStr(findElement(Of Integer)(integerArray, integerSearch)))
    MsgBox(CStr(findElement(Of Date)(dateArray, dateSearch)))
End Sub

The preceding calls to MsgBox display "0", "1", and "-1" respectively.

See also