Time
Class Case Study: Extension MethodsYou can use extension methods to add functionality to an existing type without modifying the type’s source code. You saw in Section 9.3.3 that LINQ’s capabilities are implemented as extension methods. Figure 10.16 uses extension methods to add two new methods to class Time2
(Section 10.5)—DisplayTime
and AddHours
.
DisplayTime
The extension method DisplayTime
(lines 35–38) displays the string
representation of the time in the console window. The key new feature of method DisplayTime
is the this
keyword that precedes the Time2
parameter in the method header (line 35)—this notifies the compiler that DisplayTime
is an extension method for an existing class (Time2
). The type of an extension method’s first parameter specifies the type of object on which you can call the method—for this reason, each extension method must define at least one parameter. Also, extension methods must be defined as static
methods in a static
class such as TimeExtensions
(lines 32–53). A static
class can contain only static
members and cannot be instantiated.
DisplayTime
Line 14 uses Time2
object myTime
to call the DisplayTime
extension method. Note that we do not provide an argument to the method call. The compiler implicitly passes the object that calls the method (myTime
) as the extension method’s first argument. This allows you to call DisplayTime
as if it were a Time2
instance method. In fact, IntelliSense displays extension methods with the class’s instance methods and identifies them with a distinct icon
The down-arrow in the icon denotes an extension method. Also, when you select an extension method in the IntelliSense window, the tool tip that describes the method includes the text (extension) for each extension method.
AddHours
Lines 42–52 of Fig. 10.16 declare the AddHours
extension method. Again, the this
keyword in the first parameter’s declaration indicates that AddHours
can be called on a Time2
object. The second parameter is an int
value specifying the number of hours to add to the time. The AddHours
method returns a new Time2
object with the specified number of hours added.
Lines 45–46 create the new Time2
object and use an object initializer to set its Minute
and Second
properties to the corresponding values in the parameter aTime
—these are not modified when we add hours to the time. Line 49 adds the second argument’s number of hours to the original Time2
object’s Hour
property, then uses the %
operator to ensure the value remains in the range 0–23. The result is assigned to the new Time2
object’s Hour
property. Line 51 returns the new Time2
object to the caller.
AddHours
Line 18 calls the AddHours
extension method to add five hours to the myTime
object’s hour value. Note that the method call specifies only one argument—the number of hours to add. Again, the compiler implicitly passes the object that’s used to call the method (my-Time
) as the extension method’s first argument. The Time2
object returned by AddHours
is assigned to a local variable (timeAdded
) and displayed in the console using the Display-Time
extension method (line 19).
Line 23 uses both extension methods (DisplayTime
and AddHours
) in a single statement to add 15 hours to the original myTime
and display the result in the console. Multiple method calls in the same statement are known as cascaded method calls. When a method returns an object, you can follow the method call with a member access operator (.
) then call a method on the object that was returned. The methods are called from left to right. In line 23, the DisplayTime
method is called on the Time2
object returned by method AddHours
. This eliminates the need to assign the object returned by AddHours
to a variable, then call DisplayTime
in a separate statement.
Line 27 calls extension method DisplayTime
using its fully qualified name—the name of the class in which the extension method is defined (TimeExtensions
), followed by the member access operator (.
), the method name (DisplayTime
) and its argument list. Note in line 27 that the call to DisplayTime
passes a Time2
object as an argument to the method. When using the fully qualified method name, you must specify an argument for extension method’s first parameter. This use of the extension method uses the syntax of a static
method call.
If a type for which you declare an extension method already defines an instance method with the same name and a compatible signature, the instance method will shadow (i.e., hide) the extension method. Also, if a predefined type is later updated to include an instance method that shadows an extension method, the compiler does not report any errors and the extension method does not appear in IntelliSense.