Section 13.4. Casting to an Interface

   

13.4 Casting to an Interface

You can access the members (i.e., methods and properties) of an interface through the object of any class that implements the interface. Thus, you can access the methods and properties of IStorable through the Document object, as if they were members of the Document class:

 Dim doc As New Document("Test Document") doc.Status = -1 doc.Read( ) 

Alternatively, you can create an instance of the interface and then use that interface to access the methods:

 Dim isDoc As IStorable = doc isDoc.status = 0 isDoc.Read( ) 

In Chapter 15, you'll learn that at times you may create collections of objects that implement a given interface (e.g., a collection of storable objects). You can manipulate them without knowing their real type ”so long as they implement IStorable. For instance, you won't know that you have a Document object; rather you'll know only that the object in question implements IStorable. You can create a variable of type IStorable and cast your Document to that type. You can then access the IStorable methods through the IStorable variable.

When you cast you say to the compiler, "trust me, I know this object is really of this type." In this case you are saying "trust me, I know this document really implements IStorable, so you can treat it as an IStorable."

As stated earlier, you cannot instantiate an interface directly ”that is, you cannot write:

 IStorable isDoc As New IStorable( ) 

You can, however, create an instance of the implementing class and then create an instance of the interface:

 Dim isDoc As IStorable = doc 

( isDoc is a reference to an IStorable object.) This is considered a widening conversion (from Document to the IStorable interface), and so the compiler makes it work with no need for an explicit cast.

In general, it is a better design decision to access the interface methods through an interface reference. Thus, it was better to use isDoc.Read( ), than doc.Read( ), in the previous example. Access through an interface allows you to treat the interface polymorphically. In other words, you can have two or more classes implement the interface, and then by accessing these classes only through the interface, you can ignore their real runtime type and treat them simply as instances of the interface. You'll see the power of this technique in Chapter 15.

There may be instances in which you do not know in advance (at compile time) that an object supports a particular interface. For instance, given a collection of objects, you might not know whether each object in the collection implements IStorable, ICompressible, or both.

You can find out what interfaces are implemented by a particular object by casting blindly and then catching the exceptions that arise when you've tried to cast the object to an interface it hasn't implemented. The code to cast Document to ICompressible might be:

 Dim icDoc As ICompressible = doc icDoc.Compress( ) 

If it turns out that Document implements only the IStorable interface but not the ICompressible interface:

 Public Class Document     Implements IStorable 

the cast to ICompressible will fail if Option Strict is On. If you turn Option Strict Off, the code will compile, but at runtime, because of the illegal cast, the program will throw an exception:

 System.InvalidCastException: Specified cast is not valid. 

Exceptions are used to report errors and are covered in detail in Chapter 17.

You could then catch the exception and take corrective action, but this approach is ugly and evil, and you should not do things this way. This is like testing whether a gun is loaded by firing it; it's dangerous and it annoys the neighbors.

Rather than firing blindly, you would like to be able to ask the object if it implements an interface, in order to then invoke the appropriate methods. VB.NET provides the is operator to help you ask the object if it implements an interface.

13.4.1 The Is Operator

The Is operator lets you query whether an object implements an interface. You use the Is operator with the TypeOf keyword, as follows :

  TypeOf   expression   Is   type  

The Is operator evaluates true if the expression (which must be a reference type, e.g., an instance of a class) can be safely cast to type (e.g., an interface) without throwing an exception.

Example 13-3 illustrates the use of the Is operator to test whether a Document object implements the IStorable and ICompressible interfaces.

Example 13-3. The Is operator
 Option Strict On Imports System Namespace InterfaceDemo     Interface IStorable         Sub Read( )         Sub Write(ByVal obj As Object)         Property Status( ) As Integer     End Interface 'IStorable     ' here's the new interface     Interface ICompressible         Sub Compress( )         Sub Decompress( )     End Interface 'ICompressible     ' Document implements both interfaces     Public Class Document         Implements IStorable         ' the document constructor         Public Sub New(ByVal s As String)             Console.WriteLine("Creating document with: {0}", s)         End Sub 'New         ' implement IStorable         Public Sub Read( ) Implements IStorable.Read             Console.WriteLine("Implementing the Read Method for IStorable")         End Sub 'Read         Public Sub Write(ByVal o As Object) Implements IStorable.Write             Console.WriteLine( _               "Implementing the Write Method for IStorable")         End Sub 'Write         Public Property Status( ) As Integer Implements IStorable.Status             Get                 Return Status             End Get             Set(ByVal Value As Integer)                 Status = Value             End Set         End Property         ' hold the data for IStorable's Status property         Private myStatus As Integer = 0     End Class 'Document     Class Tester         Public Sub Run( )             Dim doc As New Document("Test Document")             ' only cast if it is safe             If TypeOf doc Is IStorable Then                 Dim isDoc As IStorable = doc                 isDoc.Read( )             Else                 Console.WriteLine("Could not cast to IStorable")             End If             ' this test will fail             If TypeOf doc Is ICompressible Then                 Dim icDoc As ICompressible = doc                 icDoc.Compress( )             Else                 Console.WriteLine("Could not cast to ICompressible")             End If         End Sub 'Run         Shared Sub Main( )             Dim t As New Tester( )             t.Run( )         End Sub 'Main     End Class 'Tester End Namespace 'InterfaceDemo 
  Output:  Creating document with: Test Document Implementing the Read Method for IStorable Could not cast to ICompressible 

In Example 13-3, the Document class implements only IStorable:

 Public Class Document     Implements IStorable 

In the Run( ) method of the Tester class, you create an instance of Document:

 Dim doc As New Document("Test Document") 

and you test whether that instance is an IStorable (that is, does it implement the IStorable interface?):

 If TypeOf doc Is IStorable Then 

If so, you create an instance of the IStorable interface and call an interface method ( isDoc.Read ):

 Dim isDoc As IStorable = doc isDoc.Read( ) 

You then repeat the test with ICompressible, and if the test fails, you print an error message:

 If TypeOf doc Is ICompressible Then     Dim icDoc As ICompressible = CType(doc, ICompressible)     icDoc.Compress( ) Else     Console.WriteLine("Could not cast to ICompressible") End If 

The output shows that the first test (IStorable) succeeds (as expected) and the second test, of ICompressible fails, also as expected.

 Implementing the Read Method for IStorable Could not cast to ICompressible 
   


Learning Visual Basic. NET
Learning Visual Basic .Net
ISBN: 0596003862
EAN: 2147483647
Year: 2002
Pages: 153
Authors: Jesse Liberty

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