Overriding Interface Implementations

An implementing class is free to mark any or all of the methods from the interface as virtual. Derived classes can then override or provide new implementations, just as they might with any other virtual instance method.

For example, a Document class might implement the IStorable interface and mark its Read( ) and Write( ) methods as virtual. In an earlier example, we created a base class Note, and a derived class Document. While the Note class implements Read( ) and Write( ) to save to a file, the Document class might implement Read( ) and Write( ) to read from and write to a database.

Example 13-5 strips down the complexity of the previous examples and illustrates overriding an interface implementation. Note implements the IStorable-required Read( ) method as a virtual method, and Document overrides that implementation.

Tip

Notice that Note does not mark Write( ) as virtual. You’ll see the implications of this decision in the analysis that follows Example 13-5.

The complete listing is shown in Example 13-5.

Example 13-5. Overriding an interface implementation

using System;


namespace OverridingAnInterfaceImplementation
{
   interface IStorable
   {
      void Read(  );
      void Write(  );
   }

   public class Note : IStorable
   {
      public Note( string s )
      {
         Console.WriteLine(
         "Creating Note with: {0}", s );
      }

      // NB: virtual
      public virtual void Read(  )
      {
         Console.WriteLine(
         "Note Read Method for IStorable" );
      }

      // NB: Not virtual!
      public void Write(  )
      {
         Console.WriteLine(
         "Note Write Method for IStorable" );
      }
   }

   public class Document : Note
   {
      public Document( string s ):
      base( s )
      {
         Console.WriteLine(
         "Creating Document with: {0}", s );
      }

      // override the Read method
      public override void Read(  )
      {
         Console.WriteLine(
         "Overriding the Read method for Document!" );
      }

      // implement my own Write method
      public new void Write(  )
      {
         Console.WriteLine(
         "Implementing the Write method for Document!" );
      }
   }

   class Tester
   {
      public void Run(  )
      {
         Note theNote = new Document( "Test Document" );

         theNote.Read(  );
         theNote.Write(  );

         Console.WriteLine( "
" );

         IStorable isStorable = theNote as IStorable;
         if ( isStorable != null )
         {
            isStorable.Read(  );
            isStorable.Write(  );
         }
         Console.WriteLine( "
" );

         // This time create a reference to the derived type
         Document theDoc = new Document( "Second Test" );

         theDoc.Read(  );
         theDoc.Write(  );
         Console.WriteLine( "
" );

         IStorable isStorable2 = theDoc as IStorable;
         if ( isStorable != null )
         {
            isStorable2.Read(  );
            isStorable2.Write(  );
         }
      }

      static void Main(  )
      {
         Tester t = new Tester(  );
         t.Run(  );
      }
   }
}

The output looks like this:

    Creating Note with: Test Document
    Creating Document with: Test Document
    Overriding the Read method for Document!
    Note Write Method for IStorable


    Overriding the Read method for Document!
    Note Write Method for IStorable


    Creating Note with: Second Test
    Creating Document with: Second Test
    Overriding the Read method for Document!
    Implementing the Write method for Document!


    Overriding the Read method for Document!
    Note Write Method for IStorable

In Example 13-5, the IStorable interface is simplified for clarity’s sake:

    interface IStorable
    {
     void Read(  );
     void Write(  );
    }

The Note class implements the IStorable interface:

    public class Note : IStorable

The designer of Note has opted to make the Read( ) method virtual but not to make the Write( ) method virtual:

    public virtual void Read(  )
    public void Write(  )

Tip

In a real-world application, you would almost certainly mark both methods as virtual, but I’ve differentiated them to demonstrate that the developer is free to pick and choose which methods are made virtual.

The new class, Document, derives from Note:

    public class Document : Note

It is not necessary for Document to override Read( ), but it is free to do so and has done so here:

    public override void Read(  )

To illustrate the implications of marking an implementing method as virtual, the Run( ) method calls the Read( ) and Write( ) methods in four ways:

  • Through the Note class reference to a Document object

  • Through an interface created from the Note class reference to the Document object

  • Through a Document object

  • Through an interface created from the Document object

Virtual implementations of interface methods are polymorphic, just like the virtual methods of classes.

When you call the non-polymorphic Write( ) method on the IStorable interface cast from the derived Document, you actually get the Note’s Write method, because Write( ) is implemented in the base class and is non-virtual.

To see polymorphism at work with interfaces, you’ll create a reference to the Note class and initialize it with a new instance of the derived Document class:

    Note theDocument = new Document("Test Document");

Invoke the Read and Write methods:

    theDocument.Read(  );
    theDocument.Write(  );

The output reveals that the (virtual) Read( ) method is called polymorphically—that is, the Document class overrides the Note class’s Read( ), while the non-virtual Write( ) method of the Note class is invoked because it was not made virtual.

    Overriding the Read method for Document!
    Note Write Method for IStorable

The overridden method of Read( ) is called because you’ve created a new Document object:

    Note theDocument =new Document("Test Document");

The non-virtual Write method of Note is called because you’ve assigned theDocument to a reference to a Note:

Note theDocument = new Document("Test Document");

To illustrate calling the methods through an interface that is created from the Note class reference to the Document object, create an interface reference named isDocument. Use the as operator to cast the Note (theDocument) to the IStorable reference:

    IStorable isDocument = theDocument as IStorable;

Then invoke the Read( ) and Write( ) methods for theDocument through that interface:

    if (isDocument != null)
    {
     isDocument.Read(  );
     isDocument.Write(  );
    }

The output is the same: once again, the virtual Read( ) method is polymorphic, and the non-virtual Write( ) method is not:

    Overriding the Read method for Document
    Note Write Method for IStorable

Next, create a second Document object, this time assigning its address to a reference to a Document, rather than a reference to a Note. This will be used to illustrate the final cases (a call through a Document object and a call through an interface created from the Document object):

    Document Document2 = new Document("Second Test");

Call the methods on the Document object:

    Document2.Read(  );
    Document2.Write(  );

Again, the virtual Read( ) method is polymorphic, and the non-virtual Write( ) method is not, but this time you get the Write( ) method for Document because you are calling the method on a Document object:

    Overriding the Read method for Document!
    Implementing the Write method for Document!

Finally, cast the Document object to an IStorable reference and call Read( ) and Write( ):

    IStorable isDocument2 = Document2 as IStorable;
    if (isDocument != null)
    {
     isDocument2.Read(  );
     isDocument2.Write(  );
    }

The Read( ) method is called polymorphically, but the Write( ) method for Note is called because Note implements IStorable, and Write( ) is not polymorphic:

    Overriding the Read method for Document!
    Note Write Method for IStorable
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset