This appendix summarizes generic classes, extensions, and methods. Example program GenericExamples, which is available for download on the book's web site, demonstrates each of these.
The final section in this appendix describes items that you cannot make generic.
The syntax for declaring a generic class is as follows:
[attribute_list
] [Partial] [accessibility
] [Shadows] [inheritance
] _ Class name [(Oftype_list
)] [Inheritsparent_class
] [Implementsinterface
]statements
End Class
All of these parts of the declaration are the same as those used by a normal (non-generic) class. See Chapter 26, "Classes and Structures," and Appendix K for information about non-generic classes.
The key to a generic class is the (Of type_list) clause. Here, type_list is a list of data types separated by commas that form the generic's parameter types. Each type can be optionally followed by the keyword As and a list of constraints that the corresponding type must satisfy. The constraint list can contain any number of interfaces and, at most, one class. It can also contain the New keyword to indicate that the corresponding type must provide an empty constructor. If a constraint list contains more than one item, the list must be surrounded by braces.
The following code defines the generic MyGeneric class. It takes three type parameters. The first is named Type1 within the generic's code and has no constraints. The second type, named Type2, must satisfy the IComparable interface. The third parameter, named Type3, must provide an empty constructor, must satisfy the IDisposable interface, and must inherit directly or indirectly from the Person class.
Public Class MyGeneric(Of _ Type1, Type2 As IComparable, Type3 As {New, IDisposable, Person})
Due to their somewhat idiosyncratic nature, extension methods add an extra level of complexity to generics.
Normally, a generic class declaration includes the types on which it depends and what code within the class can use those types. For example, consider the Schedule class shown in the following code, which represents a schedule of tasks:
' Represents a schedule of Tasks. Public Class Schedule(Of Task) Public Sub AddTask(ByVal new_task As Task) ... End Sub ... End Class
The type list for the Schedule class includes a type named Task and the class's code can use the type Task. In this example, the AddTask subroutine takes a parameter of this type.
Now suppose you want to add an extension method named Prioritize to the generic Schedule class. The first parameter in the extension method's declaration indicates the class that the method extends. In this case, that should be Schedule(Of Task), but the extension method itself must also be generic, so it must use a type list just as any other generic method does.
The result is the following declaration. The Prioritize method first includes a type list indicating that it generically depends on a type named T within this method. It then includes the extension method parameter list. The first parameter (the only parameter in this example) gives the class that the method extends: Schedule(Of T).
Public Module ScheduleExtensions ' Prioritizes the schedule. <Extension()> Sub Prioritize(Of T)(ByVal sched As Schedule(Of T)) Debug.WriteLine("Prioritizing Schedule of " & GetType(T).Name) ... End Sub End Module
The following code fragment shows how a program could create a Schedule of Job objects and then call the Prioritize extension:
Dim sched As New Schedule(Of Job) ... sched.Prioritize()
Generic extension methods can become extremely complicated. For more detailed information about extension methods in general, see Chapter 17, "Subroutines and Functions," and the Microsoft Visual Basic Team blog post at blogs.msdn.com/vbteam/pages/articles-about-extension-methods.aspx
, paying special attention to Part 5, "Generics and Extension Methods."
In addition to generic classes and extension methods, you can create generic methods. This is simply a method that takes generic parameters. The following code shows a Switcher class that has a shared generic Switch method:
Public Class Switcher Public Shared Sub Switch(Of T)(ByRef thing1 As T, ByRef thing2 As T) Dim temp As T = thing1 thing1 = thing2 thing2 = temp End Sub End Class
The Switcher class is not generic, but it contains a generic method. Both generic and non-generic classes can define both generic and non-generic methods.
Unfortunately (or perhaps fortunately because this could be extremely complicated and confusing), you cannot make generic lambda functions. The following code shows a lambda function that is allowed and a generic lambda function that is not allowed:
' Allowed. Dim max_index1 = Function(lst As List(Of Integer)) lst.Count - 1 ' Prohibited. Dim max_index2 = Function(Of T)(lst As List(Of T)) lst.Count - 1
You also cannot make generic properties, operators, events, or constructors.