Interfaces and Polymorphism          
                                                     
Let’s suppose our company started using independent contractors. Contractors (technically) are not employees,
so we do not want to derive a new class from Employee. Furthermore, contractors are demanding creatures so
they prefer a method called PayMe() instead of ComputePay(). Is there a way to include contractors without
changing the code in ComputePayroll()?

Here is the class diagram:





























By defining an interface, we can link the entire Employee hierarchy and the Contractor class. An interface
defines a common set of behaviors. They are useful whenever classes share related behaviors, but otherwise do
not exhibit an “Is-A” relationship. Remember, inheritance models an “Is-A” relationship.

Here is the class diagram with the IPayable interface mixed in:
      •        The IPayable interface links the two previously unrelated classes.




































Here is the IPayable interface and the required updates to Employee.  Notice that:
      •        Interface methods never have an implementation.
      •        Since all derived classes override this function, they all implement the IPayable interface.


Public Interface IPayable
   Function ComputePay() As Double
End Interface

Public MustInherit Class Employee
  
 Implements IPayable

   Public MustOverride Function ComputePay() As Double _
      
Implements IPayable.ComputePay
...
End Class


Here is the Contractor implementation. We can map this implementation of PayMe to the ComputePay method
defined in the IPayable interface.


Public Class Contractor
   Implements IPayable

   Function PayMe() As Double Implements IPayable.ComputePay
      Return 10000
   End Function

End Class


Now ComputePayroll() only requires a small change. Instead of an array of Employee objects and children, we
now accept an array containing objects that implement the IPayable interface. For Contractor objects, this call
to ComputePay will actually execute the PayMe method.


Private Function ComputePayroll(ByVal Staff() As IPayable) As Double
   Dim result As Double
   Dim I As Integer

   For I = 0 To Staff.Length - 1
      result += Staff(I).ComputePay()
   Next

   Return result
End Function


Let’s test this out in the Main:


'In Main  
Dim contract As New Contractor()

Console.WriteLine("Wage:     " & wage.ComputePay())
Console.WriteLine("Sale:     " & sale.ComputePay())
Console.WriteLine("Manager:  " & manager.ComputePay())
Console.WriteLine("Contract: " & contract.PayMe())

Dim staff(3) As IPayable
staff(0) = wage
staff(1) = sale
staff(2) = manager
staff(3) = contract
Console.WriteLine("Payroll:  " & ComputePayroll(staff))















Type Casting                                                                                        
Let’s define a simple function to look at the issue of type casting. Note that all types passed in are implicitly
"cast" to an IPayable type.


Public Sub ShowPay(ByVal Payee As IPayable)      
   Console.WriteLine(Payee.ComputePay())      
End Sub


The rules for implicit type casting can be summarized as:
      •        It is always safe to cast from a specific type to a more generic type. For example, from
               SalesEmployee to Employee.
      •        You can implicitly cast from a smaller numerical type to larger one. For example, Short to Integer.

Here are some examples:


'Create some variables to work with    
Dim sale As New SalesEmployee("Sales", 5, 5)
Dim emp As Employee
    
'Cast from specific to generic. OK!
emp = sale
    
'Casting from Employee to IPayable. OK!
ShowPay(emp)
    
'Again cast from specific to generic. Remember everything
'derives from System.Object.
Dim obj As Object = sale

'OOPS! Going from generic to specific yields an error!
emp = obj


Looking again at the last line of the above example, the 'obj' reference is typed as Object, but we know that it is
actually referring to a SalesEmployee instance. SalesEmployee derives from Employee, so technically, ‘emp =
obj’ is valid. In fact, it is valid, but we have to explicitly cast it. To explicitly cast, you use the built in CType
function. Note: if we specified 'Option Strict Off' at the top of the source file then we would not have to do an
explicit cast in this case. However, most of the time we want the extra compiler validation that Option Strict
provides.


'OOPS! Going from generic to specific yields a compiler error!
emp = obj

'We can make this work with an explicit cast
emp = CType(obj, Employee)


VB  also provides the new DirectCast() keyword, which is used for the same purpose as CType(). However,
unlike CType(), DirectCast() can only be used it the types are related by inheritance or interface
implementation. DirectCast() can result in better performance than CType(), however in most cases, the gains
are negligible.


'We can make this work with an explicit cast
emp = DirectCast(obj, Employee)


Of course, explicit casting only works if the object derives from or implements the specified type. For example,
this is an invalid cast which can be caught using Try / Catch:


'Cast an employee to a car? Don't think so!
'Runtime error!
Try
  Dim viper As Car
  viper = DirectCast(emp, Car)

Catch ex As InvalidCastException
  Console.WriteLine(ex.Message)

End Try


VB  also provides the TryCast() keyword. Syntactically, TryCast() looks identical to DirectCast(). The
difference is that TryCast() return Nothing if the arguments are not related by inheritance or interface
implementation, rather than throwing a runtime exception. Thus, rather than wrapping a call to CType() or
DirectCast() within Try / Catch logic, you can simply test the returned reference.


' TryCast() returns Nothing if the types are not
' compatible.
Dim c As Car = TryCast(myViper, Car)

If c Is Nothing Then
  Console.WriteLine("Sorry, types are not compatable...")
Else
  Console.WriteLine(c.ToString())
End If


Finally, VB  supports the TypeOf/Is syntax for testing at runtime if an object extends a given base class or
implements a particular interface. This syntax results in a Boolean return value, so it is perfect for If / Else logic.


If TypeOf sale Is Employee Then
  ' sale is an instance of Employee so use it...
End If
    
Console.WriteLine("Is the sale object an instance of...")
Console.WriteLine(" SalesEmployee?" & (TypeOf sale Is SalesEmployee))
Console.WriteLine(" WageEmployee? " & _
                (TypeOf sale Is WageEmployee))
Console.WriteLine(" Employee? " & (TypeOf sale Is Employee))
Console.WriteLine(" IPayable? " & (TypeOf sale Is IPayable))
Console.WriteLine(" Car? " & (TypeOf sale Is Car))


Given the relationship we have established in this chapter, the previous code would output the following:
Copyright (c) 2008.  Intertech, Inc. All Rights Reserved.  This information is to be used exclusively as an
online learning aid.  Any attempts to copy, reproduce, or use for training is strictly prohibited.
Interfaces and Polymorphism
Table of Contents
Courseware
Training Resources
Tutorials
Services