Variations of Generic Declaration

If there were a minimum federal government data type placeholder requirement, the implementation of generics just described would certainly meet it. It's kind of nice to postpone the definition of data types until the last minute. But .NET generics don't stop there.

Multiple Placeholders

Generic placeholdersalso known as type parametersare like those knives you buy on late-night TV. You don't get one; you get more! As many as you need, it turns out. Each generic class can include multiple placeholders by adding them to the initial Of clause.

Class MultiTypes(Of T1, T2)    Public Member1 As T1    Public Member2 As T2 End Class 

As before, you aren't required to use the boring names T1 and T2. Whatever names you choose, include them as a comma-separated list just after the Of keyword. When you're ready to create an instance, replicate the comma-delimited list in the same order, but using actual types. In this statement, Integer replaces T1, while String replaces T2.

Dim useInstance As MultiTypes(Of Integer, String) 

Data Type and Interface Constraints

The type parameters you included in a generic, such as T, accept any valid data type, including Integer, String, System.Windows.Forms.Form, or your own custom types. That is, T can be replaced by anything that derives from System.Object, which is everything. You can even imagine the statement:

Class SomeClass(Of T) 

being replaced by:

Class SomeClass(Of T As System.Object) 

adding the As clause to make it look like other Visual Basic declarations. Well, you can stop imagining and start acting: Placeholders support the As clause. If you don't include an As clause, Visual Basic assumes you mean As System.Object, but you can follow As with any type you want.

Class FormOnlyClass(Of T As System.Windows.Forms.Form) 

By adding a specific class with the As clause, you enforce a constraint on the generic type, a limitation that must be met to use the type. In this case, the constraint says, "You may supply any class value for T as long as it is or it derives from System.Windows.Forms.Form. This means you can create an instance of FormOnlyClass using one of your application's forms, but not using non-Form classes.

' ----- This works. Dim usingForm As FormOnlyClass(Of Form1) ' ----- This doesn't work. Dim usingForm As FormOnlyClass(Of Integer) 

When you add a constraint to a type parameter, it impacts the features you can use with that type parameter. Consider this generic class destined to work with forms, but not declared that way.

Class WorkWithForms(Of T)    Public Sub ChangeCaption(ByVal whichForm As T, _          ByVal newCaption As String)       ' ----- The following line will not compile.       whichForm.Text = newCaption    End Sub End Class 

In this class, the assignment to whichForm.Text will fail because the WorkWithForms class does not know that you plan to use it with forms. It only knows that you plan to use T, and T is, by default, of type System.Object. There's no Text property in the System.Object class; I checked.

If we change the definition of WorkWithForms to accept Form objects, the outlook for compiling this code changes dramatically.

Class WorkWithForms(Of T As Windows.Forms.Form)    Public Sub ChangeCaption(ByVal whichForm As T, _          ByVal newCaption As String)       ' ----- Yes! It now compiles.       whichForm.Text = newCaption    End Sub End Class 

Becaue T has to be a Form type or something derived from Form, Visual Basic knows that all the members of the Form class, including Text, are available to all things T. Therefore, the assignment to whichForm.Text works.

In addition to classes, you can also use interfaces to constrain your generic types.

Class ThrowAwayClass(Of T As IDisposable) 

Instances of ThrowAwayClass can be created as needed, but only if the type supplied with the declaration implements the IDisposable interface.

' ----- This works. Pens use IDisposable. Dim disposablePen As ThrowAwayClass(Of System.Drawing.Pen) ' ----- This doesn't work, since the Integer data type '       doesn't implement IDisposable. Dim disposableNumber As ThrowAwayClass(Of Integer) 

But wait, there's more! See, I told you it was like shopping for knives on TV. Besides your run-of-the-mill types and interfaces, you can also follow the As clause on the generic placeholder with the New keyword.

Class SomeClass(Of T As New) 

The As New clause says to the generic type, "Accept any type for T, but only if that type includes a constructor that requires no arguments." That is, T must include a default constructor. Once defined, you'll be able to create new instances of Twhatever type it actually turns out to bein your generic type.

Class SomeClass(Of T As New)    Public Sub SomeSub()       Dim someVariable As New T    End Sub End Class 

If your generic class includes multiple type parameters, each parameter can include its own As class with a distinct type or interface constraint.

Simultaneous Constraints

It's nice that each of those knives you purchased can slice a watermelon, but what if you want to chop wood with that same knife, or use it to upgrade that electrical work you've been postponing? You're looking for a multi-functional tool, just like you find in each generic placeholder. If you need one placeholder to include a constraint for a specific class, an interface, and "New" all at once, you can do it. After the As keyword, include the multiple constraints in curly braces.

Class SomeClass(Of T As {Windows.Forms.Form, _    IDisposable, New}) 

Now, any type you supply in the Of clause when creating an instance of this class must meet all of the constraints, not just one of them. And here's something new: You can include more than one interface constraint at a time.

Class SomeClass(Of T As {ISerializable, IDisposable}) 

And you can still include a class constraint and the New constraint, even with those multiple interfaces. (You can't include more than one class constraint for a single placeholder.) If your generic type includes multiple type parameters, each of them can have their own multiple constraints set.

Nesting Generic Types

Generic types can include their own nested types.

Class Level1(Of T1)    Public Level1Member As T1    Class Level2(Of T2)       Public Level2Member1 As T1       Public Level2Member2 As T2    End Class End Class 

You can nest the generics as deeply as you need.

Non-Generic Types with Generic Members

If generic types seem a little scary or overwhelming, don't fret. You don't have to create a full generic type to use the new generic features. You can add generic support to just a single method within an otherwise normal class.

Class SomeClass    ' ----- The class itself does not have the generic    '       Of clause, so it's not generic. But...    Public Shared Sub ReverseValues(Of T) _          (ByRef first As T, ByRef second As T)       ' ----- This method is generic with its own Of clause.       ' ----- Reverse the contents of two variables.       Dim holdFirst As T       holdFirst = first       first = second       second = holdFirst    End Sub End Class 

Generic methods are useful when you need to have a local variable of the placeholder's type within the method (as is done with holdFirst here), but you don't know the type in advance. Using this shared ReverseValues method works like any other method, with the extra Of clause stuck in.

Dim x As Integer = 5 Dim y As Integer = 10 SomeClass.ReverseValues(Of Integer)(x, y) MsgBox(x)  ' Displays 10 

If you will be using the placeholder for one or more of the method arguments, Visual Basic will infer the type based on the passed value. If Visual Basic is able to guess the type in this way, you don't even need the Of clause when calling the generic method.

SomeClass.ReverseValues(x, y) 

As with generic types, generic methods allow you to add constraints to the placeholders.

Overloading Generic Types and Members

Earlier I mentioned how the compiler essentially creates separate classes for each instance variation of a generic class that you create. This means that these two instances actually use completely different and generally unrelated classes.

Dim numberVersion As SomeClass(Of Integer) Dim textVersion As SomeClass(Of String) 

So SomeClass(Of Integer) and SomeClass(Of String) are completely different classes, even though they have the same base name. In a way, Visual Basic is overloading the class name for you, letting you use it in two (or more) different ways.

Generics also let you get involved in the class-overloading game. Normally, you can only create a single class with a given name (inside of a particular namespace, that is). But with generics, you can reuse a class name, as long as the placeholders used among the classes are different enough, either in their number or in their applied constraints.

Class SomeClass(Of T1)    ' ----- This is a generic class with one placeholder. End Class Class SomeClass(Of T1, T2)    ' ----- This is a completely different generic    '       class with two placeholders. End Class 

Visual Basic will figure out which version to use based on the Of clause you include with the instance declaration.

Dim simpleVersion As SomeClass(Integer) Dim complexVersion As SomeClass(Integer, String) 

Start-to-Finish Visual Basic 2005. Learn Visual Basic 2005 as You Design and Develop a Complete Application
Start-to-Finish Visual Basic 2005: Learn Visual Basic 2005 as You Design and Develop a Complete Application
ISBN: 0321398009
EAN: 2147483647
Year: 2006
Pages: 247
Authors: Tim Patrick

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: