Recipe 3.16. Enforcing Strong Data Typing in an Otherwise Weakly Typed Collection


Problem

You have created a generic collection class that is quite useful and will support data of any class or type. You want to ensure that data types are never mixed within a single instance of the collection. That is, if a collection contains String values, you never want Integer values added to that same collection.

Solution

Use generics to restrict the types of data interactions a class may have.

Discussion

Generics allow you to make substitutions of generic data-type placeholders with actual data types. Consider this simple class:

 Class MultiShow    Public DisplayValue As String    Public InterValue As String    Public Sub ShowDouble()       ' ----- Display two copies of the value.       MsgBox(DisplayValue & InterValue & DisplayValue)    End Sub    Public Sub ShowTriple()       ' ----- Display three copies of the value.       MsgBox(DisplayValue & InterValue & DisplayValue & _          InterValue & DisplayValue)    End Sub End Class 

This class facilitates the display of some stored string value. But what if you wanted to display Integer data? You would have to rewrite the class, redefining DisplayValue and InterValue as Integer types. And that wouldn't help you much if you then wanted to use Date values. You could replace String with Object, but this approach would not help you if you needed to ensure that DisplayValue and InterValue were the same data type.

Generics allow you to treat a class in a generic manner where data types are concerned. Adding generics to our MultiShow class results in the following code:

 Class MultiShow(Of T)    Public DisplayValue As T    Public InterValue As T    Public Sub ShowDouble( )       ' ----- Display two copies of the value.       MsgBox( _          DisplayValue.ToString() & InterValue.ToString( ) & _          DisplayValue.ToString( ))    End Sub    Public Sub ShowTriple( )       ' ----- Display three copies of the value.       MsgBox( _          DisplayValue.ToString() & InterValue.ToString( ) & _          DisplayValue.ToString() & InterValue.ToString( ) & _          DisplayValue.ToString( ))    End Sub End Class 

The Of T clause enables generics on the class. T acts like a placeholder (you don't have to use T; you can give the placeholder any name you want) for a data type used somewhere in the class. In this example, we used T twice to set the data types for the public fields:

 Public DisplayValue As T Public InterValue As T 

To use this class, include an Of datatype clause in your reference declaration:

 Dim dataShow As New MultiShow(Of String) 

In the dataShow instance, String is used anywhere T appears in the class definition. It's as if Visual Basic generated a String-specific version of the MultiShow class for you. To generate an Integer version, just update the declaration:

 Dim dataShow As New MultiShow(Of Integer) 

Each instance variation of a generic class you define is truly a distinct data type. You cannot pass data freely between instances of MultiShow(Of Integer) and MultiShow(Of String) without conversion, just as you cannot pass data between Date and Integer data types without conversion.

You can include multiple data-type placeholders by separating them with commas:

 Class MultiShow(Of T1, T2)    Public DisplayValue As T1    Public InterValue As T2 

Now you can provide either identical or distinct data types for T1 and T2:

 Dim dataShowUnited As New MultiShow(Of String, String) Dim dataShowDivided As New MultiShow(Of String, Integer) 

In addition to simple data-type placeholders, you can include restrictions on each placeholder to limit the types of data used by the class. You can design a generic class that will limit the data-type substitution to just the Form class or any class derived from Form:

 Class FunForms(Of T As System.Windows.Forms.Form) End Class 

Interface-specific limits work as well:

 Class ThrowAways(Of T As System.IDisposable) End Class 

If you want to create new instances of T (whatever it is) within your class, use the As New restriction in the generic definition:

 Class EntryManager(Of T As New)    Public Function BuildNewEntry() As T       ' ----- Create a new object.       Dim result As New T       …       Return result    End Function End Class 

This works only if the data type replacing T includes a default constructor (that is, a constructor with no arguments).

Each data-type placeholder in the generic definition can include multiple constraints, all surrounded with curly braces:

 Class FunForms(Of T As {System.Windows.Forms.Form, New}) End Class 

The list of multiple restrictions can include multiple interfaces if needed, but only one standard class (such as System.Windows.Forms.Form) is permitted per placeholder.

Generics are useful when defining collection classes. Adding a generic restriction to a collection ensures that objects of only a single type can be added to the collection, a restriction that may be useful in some cases. For example, a Collection(Of String) allows only String values to be added to the collection.

See Also

Chapter 14 includes recipes that show you how to use specific generic collection classes.




Visual Basic 2005 Cookbook(c) Solutions for VB 2005 Programmers
Visual Basic 2005 Cookbook: Solutions for VB 2005 Programmers (Cookbooks (OReilly))
ISBN: 0596101775
EAN: 2147483647
Year: 2006
Pages: 400

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net