You can extend an existing interface to add new methods or members. For example, you might extend ICompressible
with a new interface, ILoggedCompressible
, which extends the original interface with methods to keep track of the bytes saved. One such method might be called LogSavedBytes( )
. The following code creates a new interface named ILoggedCompressible
that is identical to ICompressible
except that it adds the method LogSavedBytes
:
interface ILoggedCompressible : ICompressible { void LogSavedBytes( ); }
Classes are now free to implement either ICompressible
or ILoggedCompressible
, depending on whether they need the additional functionality. If a class does implement ILoggedCompressible
, it must implement all the methods of both ILoggedCompressible
and ICompressible
. Objects of that type can be cast either to ILoggedCompressible
or to ICompressible
.
Example 13-4 extends ICompressible
to create ILoggedCompressible
, and then casts the Document
first to be of type IStorable
and then to be of type ILoggedCompressible
. Finally, the example casts the Document
object to ICompressible
. This last cast is safe because any object that implements ILoggedCompressible
must also have implemented ICompressible
(the former is a superset of the latter). This is the same logic that says you can cast any object of a derived type to an object of a base type (that is, if Student
derives from Human
, then all Student
s are Human
, even though not all Humans
are Student
s).
Example 13-4. You can extend an interface to create a new interface with additional methods or members
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Example_13_4_ _ _ _Extending_Interfaces { interface ICompressible { void Compress( ); void Decompress( ); } // extend ICompressible to log the bytes saved interface ILoggedCompressible : ICompressible { void LogSavedBytes( ); } public class Document : ILoggedCompressible { public Document(string s) { Console.WriteLine("Creating document with: {0}", s); } #region public void Compress( ) { Console.WriteLine("Executing Compress"); } public void Decompress( ) { Console.WriteLine("Executing Decompress"); } public void LogSavedBytes( ) { Console.WriteLine("Executing LogSavedBytes"); } #endregion //ILoggedCompressible } class Tester { public void Run( ) { Document doc = new Document("Test Document"); ILoggedCompressible myLoggedCompressible = doc as ILoggedCompressible; if (myLoggedCompressible != null) { Console.Write(" Calling both ICompressible and "); Console.WriteLine("ILoggedCompressible methods..."); myLoggedCompressible.Compress( ); myLoggedCompressible.LogSavedBytes( ); } else { Console.WriteLine("Something went wrong! Not ILoggedCompressible"); } } static void Main( ) { Tester t = new Tester( ); t.Run( ); } } }
The output looks like this:
Creating document with: Test Document Calling both ICompressible and ILoggedCompressible methods... Executing Compress Executing LogSavedBytes
Example 13-4 starts by creating the ILoggedCompressible
interface, which extends the ICompressible
interface:
// extend ICompressible to log the bytes saved interface ILoggedCompressible : ICompressible { void LogSavedBytes( ); }
Notice that the syntax for extending an interface is the same as that for deriving from a class. This extended interface defines only one new method (LogSavedBytes( )
), but any class implementing this interface must also implement the base interface (ICompressible
) and all its members. (In this sense, it is reasonable to say that an ILoggedCompressible
object is an ICompressible
object.)