Chapter 13. Interfaces

There are times when you may not want to create a new type, but you do want to describe a set of behaviors that any number of types might implement. For example, you might want to describe what it means to be storable (capable of being written to disk) or printable.

Such a description is called an interface. An interface is a contract. When you design an interface, you’re saying “if you want to provide this capability, you must implement these methods, provide these properties and indexers, and support these events.” The implementer of the interface agrees to the contract and implements the required elements.

Tip

See Chapter 8 for information about methods and properties, Chapter 17 for information about events, and Chapter 14 for coverage of indexers.

When specifying interfaces, it is easy to get confused about who is responsible for what. There are three concepts to keep clear:

The interface

This is the contract. By convention, interface names begin with a capital I, so your interface might have a name such as IPrintable. The IPrintable interface might require, among other things, a Print( ) method. This states that any class that wants to implement IPrintable must implement a Print( ) method, but it does not specify how that method works. That is up to the designer of the implementing class.

The implementing class

This is the class that agrees to the contract described by the interface. For example, Document might be a class that implements IPrintable and thus implements the Print( ) method in whatever way the designer of the Document class thinks is appropriate.

The client class

The client calls methods on the implementing class. For example, you might have an Editor class that has a collection of IPrintable objects (every object in the class is an instance of a type that implements IPrintable). The client can expect to be able to call Print( ) on each, and while each may implement the method differently, each will do so appropriately and without complaint.

Interfaces are a critical addition to any framework, and they are used extensively throughout .NET. For example, the collection classes (stacks, queues, dictionaries) are defined, in large measure, by the interfaces they implement. (The collection classes are reviewed in detail in Chapter 14.)

In this chapter, you will learn how to create, implement, and use interfaces. You’ll learn how one class can implement multiple interfaces, and you will also learn how to make new interfaces by combining or deriving from existing interfaces. Finally, you will learn how to test whether a class has implemented an interface.

Implementing an Interface

The syntax for defining an interface is very similar to the syntax for defining a class:

    [attributes] [access-modifier] interface interface-name [:base-list] {interface-body}

The optional attributes are well beyond the scope of this book (however, see the sidebar, "Attributes“).

Access modifiers (public, private, etc.) work just as they do with classes. (See Chapter 7 for more about access modifiers.) The interface keyword is followed by an identifier (the interface name). It is common (but not required) to begin the name of your interface with a capital I (IStorable , ICloneable, IGetNoKickFromChampagne, etc.). The optional base list is discussed later in this chapter.

Attributes are most often used in one of two ways: either for interacting with legacy COM objects or for creating controls that will be fully recognized by the Visual Studio development environment. You can create your own custom attributes , but this is unusual and not covered in this book (for more on this, see Programming C#, Fourth Edition [O’Reilly, 2005]). Now suppose you are the author of a Document class, which specifies that Document objects can be stored in a database. You decide to have Document implement the IStorable interface. It isn’t required that you do so, but by implementing the IStorable interface, you signal to potential clients that the Document class can be used just like any other IStorable object. This will, for example, allow your clients to add your Document objects to an array of Notes

    IStorable[] myStorableArray = new IStorable[3];

and to otherwise interact with your Document in this very general and well-understood way.

To implement the IStorable interface, use the same syntax as if the new Document class were inheriting from IStorable—a colon (:) followed by the interface name:

    public class Document : IStorable

You can read this as “define a public class named Document that implements the IStorable interface.” The compiler distinguishes whether the colon indicates inheritance or implementation of an interface by checking to see if IStorable is defined, and whether it is an interface or base class.

Tip

If you derive from a base class and you also implement one or more interfaces, you use a single colon and separate the base class and the interfaces by commas. The base class must be listed first; the interfaces may be listed in any order.

    public MyBigClass : TheBaseClass, IPrintable, IStorable, IClaudius, IAndThou

In this declaration, the new class MyBigClass derives from TheBaseClass and implements four interfaces.

Your definition of the Document class that implements the IStorable interface might look like this:

    public class Document : IStorable
    {
         public void Read(  ) {...}
         public void Write(object obj) {...}
         // ...
    }

It is now your responsibility, as the author of the Document class, to provide a meaningful implementation of the IStorable methods. Having designated Document as implementing IStorable, you must implement all the IStorable methods, or you will generate an error when you compile. Example 13-1 illustrates defining and implementing the IStorable interface.

Example 13-1. Document class implementing IStorable

using System;namespace InterfaceDemo
{

   interface IStorable
   {
      void Read(  );
      void Write( object obj );
      int Status { get; set; }

   }

   public class Document : IStorable
   {
      // store the value for the IStorable required property
      private int status = 0;

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

#region IStorable

      public void Read(  )
      {
         Console.WriteLine(
         "Implementing the Read Method for IStorable" );
      }

      public void Write( object o )
      {
         Console.WriteLine(
         "Implementing the Write Method for IStorable" );
      }

      public int Status
      {
         get { return status; }
         set { status = value; }
      }
#endregion

   }

   class Tester
   {
      public void Run(  )
      {
         Document doc = new Document( "Test Document" );
         doc.Status = -1;
         doc.Read(  );
         Console.WriteLine( "Document Status: {0}", doc.Status );
      }

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

The output looks like this:

    Creating document with: Test Document
    Implementing the Read Method for IStorable
    Document Status: -1

Defining the Interface

In Example 13-1, the first few lines define an interface, IStorable, which has two methods (Read( ) and Write( )) and a property (Status) of type int:

    interface IStorable
     {
         void Read(  );
         void Write(object obj);
         int Status { get; set; }
     }

Notice that the IStorable method declarations for Read( ) and Write( ) do not include access modifiers (public, protected, internal, private). In fact, providing an access modifier generates a compile error. Interface methods are implicitly public because an interface is a contract meant to be used by other classes. In addition, you must declare these methods to be public, and not static, when you implement the interface.

In the interface declaration, the methods are otherwise defined just like methods in a class: you indicate the return type (void), followed by the identifier (Write), followed by the parameter list (object obj), and, of course, you end all statements with a semicolon.

An interface can also require that the implementing class provide a property (see Chapter 8 for a discussion of properties). Notice that the declaration of the Status property does not provide an implementation for get( ) and set( ), but simply designates that there is a get( ) and a set( ):

    int Status { get; set; }

Implementing the Interface on the Client

Once you’ve defined the IStorable interface, you can define classes that implement your interface. Keep in mind that you cannot create an instance of an interface; instead, you instantiate a class that implements the interface.

Tip

You can make a reference to an interface, but you must assign an actual implementing object to that reference:

    IStorable myStorable = new Document(  );

The class implementing the interface must fulfill the contract exactly and completely. Thus, your Document class must provide both a Read( ) and a Write( ) method and the Status property.

    public class Document : IStorable
    {

This statement defines Document as a class that defines IStorable. I also like to separate the implementation of an interface in a region—this is a Visual Studio 2005 convenience that allows you to collapse and expand the code within the region to make reading the code easier:

    #region IStorable
      //...
    #endregion

Within the region, you place the code that implements the two required methods and the required property. Exactly how your Document class fulfills the requirements of the interface, however, is entirely up to you.

Although IStorable dictates that Document must have a Status property, it does not know or care whether Document stores the actual status as a member variable or looks it up in a database. Example 13-1 implements the Status property by returning (or setting) the value of a private member variable, status. Another class that implements IStorable could provide the Status property in an entirely different manner (such as by looking it up in a database).

..................Content has been hidden....................

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