Page 1 of 1

Using Generics in VB.Net Part II Adding Constraints to your Generics Rate Topic: -----

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1641
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Post icon  Posted 04 August 2007 - 11:11 PM

Welcome to Part II of my tutorial series on Generics in VB.Net, as you recall, in my first tutorial I gave examples of how Generics improved code re-usability, efficiency and readability of code. I gave an overview of what Generics were and how they can be used. In this tutorial I will be discussing adding Constraints in your Generics classes.

What are Constraints? Adding a Constraint to your Generics class restricts or limits the possible types that the class will accept. With a Constraint you can ensure your collection only contains or accepts reference types. It also makes it possible to restrict your collection or class to only allow types that implement a certain interface, say IComparable(Of T) or IEnumerable(Of T). You can also specify more than one Constraint for a type, you do that like (Of T As {Automobile,IEnumerable}).

First lets create a class named Automobile that implements IComparable, then a couple smaller classes that inherit from Automobile

NOTE:A class that implements IComparable has to have a CompareTo Function that implements IComparable.CompareTo

Public Class Automobile : Implements IComparable

   'Lets add some variables & properties to our class
   Public _automobileID As Integer
   Public _color As System.Drawing.Color
   Public _numDoors As Integer
   Public _transType As String

   Public Property Color() As System.Drawing.Color
	  Get
		 Return _color
	  End Get
	  Set(ByVal value As System.Drawing.Color)
		 _color = value
	  End Set
   End Property

   Public Property NumberOfDoors() As Integer
	  Get
		 Return Integer.TryParse(_numDoors,New Integer)
	  End Get
	  Set(ByVal value As Integer)
		 _numDoors = value
	  End Set
   End Property

   Public Property Transmission() As String
	  Get
		 Return _transType
	  End Get
	  Set(ByVal value As Integer)
		 _transType = value
	  End Set
   End Property

   Public ReadOnly Property AutomobileID() As Integer
	  Get
		 Return _automobileID
	  End Get
   End Property

   Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo
	  If Not (TypeOf obj Is Automobile) Then
		  Throw New ArgumentException
	  End If

	  Dim Automobile2 As Automobile = CType(obj, Automobile)
	  Dim cmpl As Integer = Me.AutomobileID.CompareTo(Automobile.AutomobileID)
	  If Not (cmpl = 0) Then
		 Return cmpl
	  End If
	  Return Me.AutomobileID.CompareTo(f2.AutomobileID)
   End Function
End Class

Public Class HotRod : Inherits Automobile
   'add your class code here
End Class

Public Class Jalopy : Inherits Automobile
   'add your class code here
End Class

Public Class Truck : Inherits Automobile
   'add your class code here
End Class



Now that we have our Automobile class, lets use this as a constraint in our TheStackClass class by restricting the types it can accept to the type Automobile We will add a 2 constraints on the original type parameter as Automobile and IComparable.

Public Class TheStackClass(Of type As {Automobile,IComparable})
   'declare the variables we need
   Private item() As type  'create a dynamic array
   private itemPointer As Integer  'Create a pointer to the item

   'instantiate the class and set its size
   Public Sub New(ByVal itemSize As Integer)
	  'Redim the dynamic array upon instantiation
	  ReDim item(itemSize - 1)
	  'set the itemPointer to zero
	  itemPointer = 0
   End Sub

   '"Push" or add an item to the stack
   Public Sub PushItem(Of Automobile)(ByVal i As type)
	  'first make sure the stack isnt full
	  If itemPointer > UBound(item) Then
		 Throw New ArgumentOutOfRangeException("The stack is currently full. Please remove an item before attempting to add a new one")
	  Else  'stack isnt full
		 item(itemPointer) = i
		 itemPointer +=1
	  End If
   End Sub

   '"Pop" or remove an item from the stack
   Public Function PopItem() As type
	  'decrement the itemPointer
	  itemPointer -= 1
	  'check to see if the stack is empty
	  If itemPointer < 0 Then  'stack is currently empty
		 Throw New ArgumentOutOfRangeException("The stack is currently empty.You cannot remove an item from an empty stack")
	  End If
	  'return the itemPointer value
	  Return item(itemPointer)
   End Function
End Class



As you notice, in the original class it was Public Class TheStackClass(Of Type), but adding the constraint Public Class TheStackTrace(Of type {Automobile,IComparable}) we have added a constraint that the only types this will now accept are Automobile and IComparable.

Also, the PushItem method we added a Constraint to that as well, changing the definition to Public Sub PushItem(Of Automobile)(ByVal i As type), yes you can add Constraints to methods within the Generic Class as well.

If we tried to now call this class the way we did originally

Dim MyStack As New TheStackClass(Of String)(4)



THis would cause a compile time error, we now have to call it like this

Dim MyStack As New TheStackClass(Of HotRod)(3)
Dim MyStack As New TheStackClass(Of Jalopy)(4)
Dim MyStack As New TheStackClass(Of Truck)(2)
'and so on.....



Notice we use the Type HotRod, this is one of the classes we have that inherits the Automobile class. Using Constraints in your Generic Type is definitely an improved way of writing code, it also makes it more efficient, easier to read and type safe.

This is a high-level overview of adding a constraint to your Generic class, though there are many more things you can do with Generics, many more constraints you can work with, Generics in VB.Net do have many more limitations than its counterpart C#. Some of the limitations are:
  • Since Generics without constraints are viewed as System.Object types, you cannot access type members not available to System.Object

  • You cannot use arithmetic operations or nested class (though constraints can be added to soften this up a little)

  • You cannot access static members or nested classes without explicit casting (Ctype(obj,TheTypeYouWant))

  • You cannot use arithmetic operations unless your base class supports them (your base class is your constraint)

  • You cannot use Generics as type arguments

So that is adding Constraints to your Generics Class, if you have questions or comments you can send me a PM and I will answer them. Better yet, post your questions here and I can answer them for you, and anyone else who may have the same question. Thank you for reading.

Happy Coding!

Is This A Good Question/Topic? 1
  • +

Replies To: Using Generics in VB.Net Part II

#2 wille45  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 28-June 08

Posted 28 June 2008 - 09:12 AM

I need help writing code without creating a form.
Was This Post Helpful? 0
  • +
  • -

#3 woodjom  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 29
  • View blog
  • Posts: 549
  • Joined: 08-May 08

Posted 11 February 2010 - 08:49 AM

Psycho,
You got a good information source as to the possible "Basic" constraints list? I know you can use the New, Class, Structure, Type, <any Interface>,etc.

But what i am trying to constrain my generic to is a Numeric type (Int, Int16, Int32, Short, Long, Double, etc). I have a core interface which contains 3 methods that must be implemented. Then i have 3 more interfaces which lay ontop of that interface. These 3 new interfaces incorporate the difference between 16, 32, and 64 bit numerics. At which point i plan on having at least 2 implementations of these 3 interfaces for 3 structure objects.

It would be great if i could have these 3 top-lvl interfaces constrained to just numeric values, so some idgiot doesnt try casting a Character or Boolean type into the generic.
Was This Post Helpful? 0
  • +
  • -

#4 ???  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 48
  • Joined: 25-November 10

Posted 05 September 2011 - 02:42 PM

It's easy

Public Interface Number(Of T As {IComparable, IFormattable, IConvertible, IComparable(Of T), IEquatable(Of T)})

End Interface


Only the primitive numeric types (byte, sbyte, int32, etc.) implement all of these interfaces
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1