Understanding Interfaces and Their UsefulnessBy Tim Stall
Many large Web applications in existence make use of User Controls, which are a unit of user interface reuse in ASP.NET. Common UI pieces - such as menus, page headers or footers, and so on - can be easily encapsulated into a User Control for reuse on numerous other pages. In their simplest form, User Controls are statically added to a Web page, dragged on from the Solution Explorer in Visual Studio .NET. However, User Controls can also be dynamically added to a page, a technique commonly used for providing customized user interfaces.
When multiple developers start building a large scale ASP.NET application that utilizes dynamically-added User Controls, the site's design often suffers from two common problems:
- Quality control, and
It is possible, though, to solve these quality control and flexibility issues through the use of .NET interfaces. This article explores how to use interfaces to simplify development of a site with dynamically loaded User Controls. (This article does not provide an in-depth look at User Controls or at techniques for dynamically loading Web controls. For more information on these topics be sure to read An Extensive Examination of User Controls and Dynamic Controls in ASP.NET.)
Working with Dynamic User Controls - The Non-Interface Solution
In order to fully understand the benefits of using interfaces when building a Web application that uses dynamically-loaded User Controls, let's first look at an example of not using interfaces. Assume that we have a page that loads one of three User Controls based upon the querystring, and that later on in the code we need to read the value of a property. If each control has a different name for the property that we want to call, we'll need to determine what control was loaded and then read its appropriate property. There are a number of ways this could be accomplished, but they all boil down to a series of conditional statements, like:
As the above example shows, one of three User Controls -
NoneC - has
its appropriate property read, based on the querystring value. By inspecting the code you'll likely find
a number of limitations that could be remedied:
- Each control has a different property name for the same functionality (
- Reading the appropriate property requires a
switchstatement that has one section for each different type of control to be loaded. If there were many types of User Controls that might be loaded, the
switchstatement could quickly become tediously long and unreadable.
- The possible User Controls are hard-coded into the
switchstatement, so we would need to modify the code if a new type of User Control could be added.
An Overview on Interfaces
Interfaces are a common concept in object-oriented programming. From the Java documentation:
In English, an interface is a device or a system that unrelated entities use to interact. According to this definition, a remote control is an interface between you and a television set, the English language is an interface between two people, and the protocol of behavior enforced in the military is the interface between people of different ranks. Within [an object-oriented] ... programming language, an interface ... is a device that unrelated objects use to interact with each other. An interface is probably most analogous to a protocol (an agreed on behavior). ....NET provides an interface type that you can use to formally spell out a list of member signatures. Any class that implements an interface, must implement the list of member signatures defined by the interface. This assists quality control by enforcing the class members to use the same names. It also assists flexibility by providing interface polymorphism, which is similar to polymorphism with base classes.
You use an interface to define a protocol of behavior that can be implemented by any class anywhere in the class hierarchy. Interfaces are useful for the following:
- Capturing similarities among unrelated classes without artificially forcing a class relationship.
- Declaring methods that one or more classes are expected to implement.
- Revealing an object's programming interface without revealing its class.
Writing an interface is quick and easy, as the code below shows:
This code creates an interface named
Notice how just like regular class files, an interface starts with the namespaces it uses, and can itself be wrapped in a
namespace. However it differs from a class by using the
interface keyword instead of the
keyword, and by having a body that is only a list of signatures without any actual implementation. This particular
interface declares a read-only property named
GetData that returns a string, and a method
Although an interface is similar to a base class, it is also very different. They are similar in that:
- Both provide structure to another class that uses them
- Both can be used for polymorphism
- A class can inherit only one base class, but it can implement many interfaces
- A base class can contain implementation, an interface cannot
- Interfaces can only contain Methods, Properties, Indexers, and Events. They cannot contain fields or constants (which are used for implementation)
Dynamically-Loaded User Controls - The Interface Solution
Once you have created an interface, the next step is to have your User Controls implement the interface. To specify that a class must implement a particular interface use the following syntax:
To have your User Control implement the
ISection interface, go to the User Control's code portion and modify the
class declaration so that it implements the interface:
If you are using Visual Studio .NET, once you enter this code you'll see a tooltip pop-up that prompt you to press TAB in order to automatically create the stub of the interface, as shown in the screenshot below.
Press TAB, and you'll see the following code created:
If you try changing the names of this property or method, or remove the property or method, you'll get a compile-time error since not all of the interfaces members will be implemented in the class. By having all of our User Controls that can be dynamically loaded implement this common interface we'll have achieved one of our goals – to have the compiler enforce standardized names of methods and properties across all controls.
Recall that without interfaces, calling a method from the dynamically-loaded control required a
structure that hard-coded each possible option. For each option we had to individually select the specific User Control's
property. Also, the IntelliSense feature in Visual Studio .NET would show us all of the properties of each individual
User Control, as shown in the screenshot below:
When using interfaces, however, our
switch statement disappears. Instead, we can reference the dynamically-loaded
User Control as an
ISection and access the appropriate property with one line of code:
Furthermore, the IntelliSense in Visual Studio .NET shows just those property and methods for the
Besides these coding benefits, we're able to develop the application faster with interfaces because:
- Visual Studio .NET automatically generates the interface stubs in our User Controls
- Calling the controls only requires one line of code as opposed to a large
switchstatement (which needs to be updated whenever new controls that might be dynamically added are created or when method names change)
- Method names for similar functions are guaranteed to be the same, making it quicker to become familiar with the application's API
Interfaces can be used at every tier of an enterprise application. While this article specifically provides an example in the presentation layer, you can benefit from interfaces at the business or data-access layers as well. Furthermore the .NET Framework itself extensively uses interfaces. Some of the common ones are for:
- Different data providers -
- Collections -
- Serialization (
ISerializable), among many others
About the Author
Tim Stall is a Chicago-based technical consultant for Computer Sciences Corporation (www.csc.com), a global IT services company.