10.6. Accessing Type Parameter MembersConsider the following generic class definition. Public Class NoisyClass(Of T) Public Sub ShowMe(ByVal theItem As T) MsgBox(theItem.ToString( )) End Sub End Class Using this class with an Integer parameter, as in: Dim notSoNoisy As New NoisyClass(Of Integer) notSoNoisy.ShowMe(5) displays a message box with the integer value, in this case, 5. You can also use other types with the class. For example, the code: Dim notSoNoisy As New NoisyClass(Of System.Exception) notSoNoisy.ShowMe(New System.Exception) displays "System.Exception: Exception of type 'System.Exception' was thrown." When T includes no class constraints, it becomes the lowest common denominator of all possible substitution types, System.Object. The definition: Public Class WorkGroup(Of T) is basically the same as: Public Class WorkGroup(Of T As System.Object) Both definitions work with all types, since all types derive from System.Object. When you add a class constraint to a type parameter (or use the default of System.Object), any members of that T class type can be used within the generic class definition. For example, consider the following simple class: Public Class ControlLocator(Of T As System.Windows.Forms.Control) Public Sub WhereIsIt(ByVal theControl As T) MsgBox("Location: " & theControl.Left & ", " & _ theControl.Top) End Sub End Class Because only types that derive from System.Windows.Forms.Control can be used as substitutes for T, all members of System.Windows.Forms.Control can be used in all references to T (such as the theControl variable), including the Left and Top properties. You can only use members that are related to the type constraints defined for a parameter. If you don't include any type constraints, then you can only use the members of System.Object, which appear in every object in .NET. Although the following class definition is slated to work with strings (and the String class's ToUpper method), it will not compile, since there is no reference to String in the type parameter's constraints. Public Class UsuallyString(Of T) Public Sub ShowUpperCase(ByVal theText As T) ' ----- The next line will not compile. MsgBox(theText.ToUpper( )) End Sub End Class Even if you create an instance of this class with a String: Dim usingStringNow As UsuallyString(Of String) the original class definition will not compile because the compiler does not know in advance that you plan to use it with String data. If you place an interface type constraint on a type parameter, uses of that type parameter can access the members of the interface, as shown in the following code. Public Interface ISimple Sub WriteThisCode( ) End Interface Public Class UsesISimple(Of T As ISimple) Public Sub DoTheWork(ByVal theData As T) ' ----- Uses the class-specific implementation. theData.WriteThisCode( ) End Sub End Class If you have multiple type constraints on a type parameter, uses of that parameter can generally access all members of all type constraints. If name conflicts do exist between two constraints (such as a class and interface having a member of the same name), your code will have to cast or convert the typed object to the desired class or interface (using CType or some other method) before calling the conflicting member. |