Section 13.1. Implementing an Interface


13.1. 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

Every .NET application contains code, data, and metadata. Attributes are objects that are embedded in your program (invisible at run time) that contain metadatathat is, data about your classes and about your program. Attributes can be made visible with ILDasm the tool for looking at the Microsoft Intermediate Language (MSIL) that the C# compiler produces.

The element to which an attribute is attached is referred to as the target of that attribute. For example, the attribute:

 [NoIDispatch] 

is associated with a class or an interface to indicate that the target should derive from IUnknown rather than IDispatch when exporting to COM.


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.

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 

13.1.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; } 

13.1.2. 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.

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).



Learning C# 2005
Learning C# 2005: Get Started with C# 2.0 and .NET Programming (2nd Edition)
ISBN: 0596102097
EAN: 2147483647
Year: 2004
Pages: 250

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