10.2 Time Class Case Study; Throwing Exceptions

Our first example consists of classes Time1 (Fig. 10.1) and Time1Test (Fig. 10.2). Class Time1 represents the time of day.1 Class Time1Test’s Main method creates an object of class Time1 and invokes its methods. The output of this app appears in Fig. 10.2.

10.2.1 Time1 Class Declaration

Class Time1 contains three public properties of type intHour, Minute and Second (Fig. 10.1, lines 7–9). These represent the time in universal-time format (24-hour clock format, in which hours are in the range 0–23). Class Time1 contains public methods Set-Time (lines 13–25), ToUniversalString (lines 28–29) and ToString (lines 32–34). These are the public services or the public interface that this class provides to its clients. In this example, class Time1 does not declare a constructor, so the compiler defines a default constructor. Each property receives the default value 0 for an int. Instance variables and auto-implemented properties also can be assigned values in their declarations.

Fig. 10.1 Time1 class declaration maintains the time in 24-hour format.

Alternate View

 1    // Fig. 10.1: Time1.cs
 2    // Time1 class declaration maintains the time in 24-hour format.
 3    using System; // namespace containing ArgumentOutOfRangeException
 4
 5    public class Time1
 6    {
 7       public int Hour { get; set; } // 0 - 23
 8       public int Minute { get; set; } // 0 - 59
 9       public int Second { get; set; } // 0 - 59
10
11       // set a new time value using universal time; throw an
12       // exception if the hour, minute or second is invalid
13       public void SetTime(int hour, int minute, int second)
14       {
15          // validate hour, minute and second
16          if ((hour < 0 || hour > 23) || (minute < 0 || minute > 59) ||
17             (second < 0 || second > 59))
18          {
19             throw new ArgumentOutOfRangeException();
20          }
21
22          Hour = hour;
23          Minute = minute;
24          Second = second;
25        }
26
27       // convert to string in universal-time format (HH:MM:SS)
28       public string ToUniversalString() =>
29           $"{Hour:D2} : {Minute:D2} : {Second:D2}";
30
31       // convert to string in standard-time format (H:MM:SS AM or PM)
32       public override string ToString() =>
33           $"{((Hour == 0 || Hour == 12) ? 12 : Hour % 12)}:" +
34           $"{Minute:D2} : {Second:D2} {(Hour < 12 ? "AM" : "PM")}";
35    }

public Class

In Fig. 10.1, we declared class Time1 as a public class, meaning that it potentially can be reused in other projects. Although we use class Time1 only in this project, from this point forward, we’ll declare as public any class that could potentially be reused in another project.

Method SetTime and Throwing Exceptions

Method SetTime (lines 13–25) is a public method that declares three int parameters and uses them to set the time. Lines 16–17 test each argument to determine whether the value is out of range. If all the values are in range, lines 22–24 assign the values to the Hour, Minute and Second properties. The hour (line 13) must be in the range 0 to 23, because universal-time format represents hours as integers from 0 to 23 (e.g., 1 PM is hour 13 and 11 PM is hour 23; midnight is hour 0 and noon is hour 12). Similarly, both minute and second values must be in the range 0 to 59. For values outside these ranges, line 19 throws an exception of type ArgumentOutOfRangeException (namespace System), which notifies the client code that an invalid argument was passed to the method. As you learned in Chapter 8, you can use try...catch to catch exceptions and attempt to recover from them, which we’ll do in Fig. 10.2. The throw statement (line 19) creates a new object of type ArgumentOutOfRangeException. The parentheses following the class name indicate a call to the ArgumentOutOfRangeException constructor. After the exception object is created, the throw statement immediately terminates method SetTime and the exception is returned to the code that attempted to set the time, where it can be caught and dealt with.

Method ToUniversalString

Method ToUniversalString (lines 28–29) is an expression-bodied method—recall this is a shorthand notation for a method that contains only a return statement. The method takes no arguments and returns a string in universal-time format, consisting of six digits—two for the hour, two for the minute and two for the second. For example, if the time were 1:30:07 PM, method ToUniversalString would return 13:30:07. The method implicitly returns the value of the string-interpolation expression in line 29. The D2 format specifier formats an integer with two digits and, where needed, a leading 0 if the integer has fewer than two digits.

Method ToString

Method ToString (lines 32–34) is an expression-bodied method that takes no arguments and returns a string in which the Hour, Minute and Second values are separated by colons and followed by an AM or PM indicator (e.g., 1:27:06 PM). Like method ToUniversal-String, method ToString implicitly returns the value of a string-interpolation expression. In this case, we do not format the Hour, but we format the Minute and Second as two-digit values with leading 0s, if necessary. Line 33 uses a conditional operator (?:) to determine the value for Hour in the string—if the hour is 0 or 12 (AM or PM), it appears as 12—otherwise, it appears as a value from 1 to 11. The conditional operator in line 34 determines whether AM or PM will be inserted in the string.

10.2.2 Using Class Time1

The Time1Test app class (Fig. 10.2) uses class Time1. Line 10 creates a Time1 object and assigns it to local variable time. Operator new invokes class Time1’s default constructor, since Time1 does not declare any constructors. Lines 13–17 output the time, first in universal-time format (by invoking time’s ToUniversalString method in line 14), then in standard-time format (by explicitly invoking time’s ToString method in line 16) to confirm that the Time1 object was initialized properly. Line 20 invokes method SetTime of the time object to change the time. Then lines 21–24 output the time again in both formats to confirm that the time was set correctly.

Fig. 10.2 Time1 object used in an app.

Alternate View

 1    // Fig. 10.2: Time1Test.cs
 2    // Time1 object used in an app.
 3    using System;
 4
 5    class Time1Test
 6    {
 7       static void Main()
 8       {
 9          // create and initialize a Time1 object
10          var time = new Time1(); // invokes Time1 constructor
11
12          // output string representations of the time
13          Console.WriteLine(
14             $"The initial universal time is: {time.ToUniversalString()}");
15          Console.WriteLine(
16             $"The initial standard time is: {time.ToString() ");
17          Console.WriteLine(); // output a blank line
18
19           // change time and output updated time
20           time.SetTime(13, 27, 6);
21          Console.WriteLine(
22              $"Universal time after SetTime is: {time.ToUniversalString()} ");
23          Console.WriteLine(
24              $"Standard time after SetTime is: {time.ToString()}");
25           Console.WriteLine(); // output a blank line
26
27           // attempt to set time with invalid values
28           try
29           {
30              time.SetTime(99, 99, 99);
31           }
32           catch (ArgumentOutOfRangeException ex)
33           {
34              Console.WriteLine(ex.Message + "
");
35           }
36
37           // display time after attempt to set invalid values
38           Console.WriteLine("After attempting invalid settings:");
39           Console.WriteLine($"Universal time: {time.ToUniversalString()} ");
40           Console.WriteLine($"Standard time: {time.ToString()} ");
41       }
42    }

The initial universal time is: 00:00:00
The initial standard time is: 12:00:00 AM

Universal time after SetTime is: 13:27:06
Standard time after SetTime is: 1:27:06 PM

Specified argument was out of the range of valid values.

After attempting invalid settings:
Universal time: 13:27:06
Standard time: 1:27:06 PM

Calling Time Method SetTime with Invalid Values

To illustrate that method SetTime validates its arguments, line 30 calls method SetTime with invalid arguments of 99 for the hour, minute and second. This statement is placed in a try block (lines 28–31) in case SetTime throws an ArgumentOutOfRangeException, which it will do since the arguments are all invalid. When this occurs, the exception is caught at lines 32–35 and the exception’s Message property is displayed. Lines 38–40 output the time again in both formats to confirm that SetTime did not change the time when invalid arguments were supplied.

Notes on the Time1 Class Declaration

Consider several class-design issues with respect to class Time1. The time is represented as three integers for the hour, minute and second. However, the actual data representation used within the class is of no concern to the class’s clients. For example, it would be perfectly reasonable for Time1 to represent the time internally as the number of seconds since midnight or the number of minutes and seconds since midnight. Clients could use the same public methods and properties to get the same results without being aware of this—of course, the Hour, Minute and Second properties would need to be reimplemented to work with the new data representation. (Exercise 10.4 asks you to represent the time as the number of seconds since midnight and show that indeed no change is visible to the clients of the class.)

Software Engineering Observation 10.1

Classes simplify programming because the client can use only the public members exposed by the class. Such members are usually client oriented rather than implementation oriented. Clients are neither aware of, nor involved in, a class’s implementation. Clients generally care about what the class does but not how the class does it. Clients do, of course, care that the class operates correctly and efficiently.

 

Software Engineering Observation 10.2

Interfaces change less frequently than implementations. When an implementation changes, implementation-dependent code must change accordingly. Hiding the implementation reduces the possibility that other parts of the app become dependent on class-implementation details.

 

Software Engineering Observation 10.3

Date and time manipulations are more complex than the simplified classes we use in this book. For applications that require date and time processing, check out .NET’s DateTimeOffest , DateTime, TimeSpan and TimeZoneInfo value types in namespace System.

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

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