Time Class Case Study: Creating Class Libraries
Time Class Case Study Creating Class Libraries
In almost every example in the text, we have seen that classes from preexisting libraries, such as the .NET Framework Class Library, can be imported into a C# application. Each class in the FCL belongs to a namespace that contains a group of related classes. As applications become more complex, namespaces help you manage the complexity of application components. Class libraries and namespaces also facilitate software reuse by enabling applications to add classes from other namespaces (as we have done in most examples). This section introduces how to create your own class libraries.
Steps for Declaring and Using a Reusable Class
Before a class can be used in multiple applications, it must be placed in a class library to make it reusable. Figure 9.16 shows how to specify the namespace in which a class should be placed in the library. Figure 9.19 shows how to use our class library in an application. The steps for creating a reusable class are:
1. |
Declare a public class. If the class is not public, it can be used only by other classes in the same assembly.
|
2. |
Choose a namespace name and add a namespace declaration to the source-code file for the reusable class declaration.
|
3. |
Compile the class into a class library.
|
4. |
Add a reference to the class library in an application.
|
5. |
Specify a using directive for the namespace of the reusable class and use the class.
|
Figure 9.16. Time1 class declaration in a namespace.
(This item is displayed on page 442 in the print version)
1 // Fig. 9.16: Time1.cs 2 // Time1 class declaration in a namespace. 3 namespace Chapter09 4 { 5 public class Time1 6 { 7 private int hour; // 0 - 23 8 private int minute; // 0 - 59 9 private int second; // 0 - 59 10 11 // set a new time value using universal time; ensure that 12 // the data remains consistent by setting invalid values to zero 13 public void SetTime( int h, int m, int s ) 14 { 15 hour = ( ( h >= 0 && h < 24 ) ? h : 0 ); // validate hour 16 minute = ( ( m >= 0 && m < 60 ) ? m : 0 ); // validate minute 17 second = ( ( s >= 0 && s < 60 ) ? s : 0 ); // validate second 18 } // end method SetTime 19 20 // convert to string in universal-time format (HH:MM:SS) 21 public string ToUniversalString() 22 { 23 return string.Format( "{0:D2}:{1:D2}:{2:D2}", 24 hour, minute, second ); 25 } // end method ToUniversalString 26 27 // convert to string in standard-time format (H:MM:SS AM or PM) 28 public override string ToString() 29 { 30 return string.Format( "{0}:{1:D2}:{2:D2} {3}", 31 ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 ), 32 minute, second, ( hour < 12 ? "AM" : "PM" ) ); 33 } // end method ToString 34 } // end class Time1 35 } // end namespace Chapter09 |
Step 1: Creating a public Class
For Step 1 in this discussion, we use the public class Time1 declared in Fig. 9.1. No modifications have been made to the implementation of the class, so we will not discuss its implementation details again here.
Step 2: Adding the namespace Declaration
For Step 2, we add a namespace declaration to Fig. 9.1. The new version is shown in Fig. 9.16. Line 3 declares a namespace named Chapter09. Placing the Time1 class inside the namespace declaration indicates that the class is part of the specified namespace. The namespace name is part of the fully qualified class name, so the name of class Time1 is actually Chapter09.Time1. You can use this fully qualified name in your applications, or you can write a using directive (as we will see shortly) and use its simple name (the unqualified class nameTime1) in the application. If another namespace also contains a Time1 class, the fully qualified class names can be used to distinguish between the classes in the application and prevent a name conflict (also called a name collision).
Only namespace declarations, using directives, comments and C# attributes (first used in Chapter 18) can appear outside the braces of a type declaration (e.g., classes and enumerations). Only class declarations declared public will be reusable by clients of the class library. Non-public classes are typically placed in a library to support the public reusable classes in that library.
Step 3: Compiling the Class Library
Step 3 is to compile the class into a class library. To create a class library in Visual C# Express, we must create a new project by clicking the File menu, selecting New Project... and choosing Class Library from the list of templates, as shown in Fig. 9.17. Then add the code from Fig. 9.16 into the new project (either by copying our code from the book's examples or by typing the code yourself). In the projects you've created so far, the C# compiler created an executable .exe containing the application. When you compile a Class Library project, the compiler creates a .dll file, known as a dynamic link librarya type of assembly that you can reference from other applications.
Figure 9.17. Creating a Class Library Project.
Step 4: Adding a Reference to the Class Library
Once the class is compiled and stored in the class library file, the library can be referenced from any application by indicating to the Visual C# Express IDE where to find the class library file (Step 4). Create a new (empty) project and right-click the project name in the Solution Explorer window. Select Add Reference... from the pop-up menu that appears. The dialog box that appears will contain a list of class libraries from the .NET Framework. Some class libraries, like the one containing the System namespace, are so common that they are added to your application implicitly. The ones in this list are not.
In the Add Reference... dialog box, click the Browse tab. Recall from Section 3.3 that when you build an application, Visual C# 2005 places the .exe file in the binRelease folder in the directory of your application. When you build a class library, Visual C# places the .dll file in the same place. In the Browse tab, you can navigate to the directory containing the class library file you created in Step 3, as shown in Fig. 9.18. Select the .dll file and click OK.
Figure 9.18. Adding a Reference.
(This item is displayed on page 444 in the print version)
Step 5: Using the Class from an Application
Add a new code file to your application and enter the code for class Time1NamespaceTest (Fig. 9.19). Now that you've added a reference to your class library in this application, your Time1 class can be used by Time1NamespaceTest (Step 5) without adding the Time1.cs source code file to the project.
Figure 9.19. Time1 object used in an application.
(This item is displayed on pages 444 - 445 in the print version)
1 // Fig. 9.19: Time1NamespaceTest.cs 2 // Time1 object used in an application. 3 using Chapter09; 4 using System; 5 6 public class Time1NamespaceTest 7 { 8 public static void Main( string[] args ) 9 { 10 // create and initialize a Time1 object 11 Time1 time = new Time1(); // calls Time1 constructor 12 13 // output string representations of the time 14 Console.Write( "The initial universal time is: " ); 15 Console.WriteLine( time.ToUniversalString() ); 16 Console.Write( "The initial standard time is: " ); 17 Console.WriteLine( time.ToString() ); 18 Console.WriteLine(); // output a blank line 19 20 // change time and output updated time 21 time.SetTime( 13, 27, 6 ); 22 Console.Write( "Universal time after SetTime is: " ); 23 Console.WriteLine( time.ToUniversalString() ); 24 Console.Write( "Standard time after SetTime is: " ); 25 Console.WriteLine( time.ToString() ); 26 Console.WriteLine(); // output a blank line 27 28 // set time with invalid values; output updated time 29 time.SetTime( 99, 99, 99 ); 30 Console.WriteLine( "After attempting invalid settings:" ); 31 Console.Write( "Universal time: " ); 32 Console.WriteLine( time.ToUniversalString() ); 33 Console.Write( "Standard time: " ); 34 Console.WriteLine( time.ToString() ); 35 } // end Main 36 } // end class Time1NamespaceTest
|
In Fig. 9.19, the using directive in line 3 specifies that we'd like to use the class(es) of namespace Chapter09 in this file. Class Time1NamespaceTest is in the global namespace of this application because the class's file does not contain a namespace declaration. Since the two classes are in different namespaces, the using directive at line 3 allows class Time1NamespaceTest to use class Time1 as if it was in the same namespace.
Recall from Section 4.4 that we could omit the using directive in line 4 if we always referred to class Console by its fully qualified class name, System.Console. Similarly, we could omit the using directive in line 3 for namespace Chapter09 if we changed the Time1 declaration in line 11 of Fig. 9.19 to use class Time1's fully qualified name, as in:
Chapter09.Time1 time = new Chapter09.Time1();