Wednesday, December 19, 2012

Extend Your Classes Without Changing Code

So I'm at a client's site and we're discussing adding a new method to an existing class. One of the client's programmers said, "We should put the method in the base class and let all the derived classes inherit it from it" Another programmer said, "I think it would be better to create a new class that inherits from our base class and add the new method to it."
And I said, "Let's not change anything. Let's just create the new method."
I had a couple of reasons for disliking the first two suggestions. First, of course they weren't my suggestions. But beyond that, I didn't want to change the base class because the base class had this neat feature: it worked. I hate making changes to working code—it's just asking for something new to fail. Adding a new derived class would avoid that problem, but creates a new one: developers would have to be told to use the new class in order to get access to the new method. Developers were already using the existing classes and I didn't see any value in making them change.
So I suggested we create an extension method and avoid all those problems. An extension method sits in a separate file from the base class, so the base class is unchanged (though the method would be in the same Class Library project and be distributed as part of the same DLL). An extension method also appears automatically in the IntelliSense dropdown lists for the existing classes, so developers would have it presented to them as part of the classes they were already using.
Creating an extension method is easy. In C#, you add a static class with a static method, with both the class and method declared as public. The method's first parameter specifies the class the method will attach itself to (the parameter has to be flagged with the this keyword).
When the extension method is used from an object, that object is automatically passed to the extension method in that parameter. This ToggleCustomerStatus method, for instance, will appear in the IntelliSense list of any Customer object (or any object that inherits from Customer), toggle the value of the Status property on the Customer object the method is used on, and return the new value:
public static class CustomerCSExtensions
{
  public static bool ToggleCustomerStatus(this Customer cust)
  {
    cust.Status = !cust.Status;
    return cust.Status;
  }
}
To create an extension method in Visual Basic, add a Module, declare it Public, write your function or subroutine, and decorate the method with the extension method. The first method parameter specifies the class to which the method will be added. When the extension method is used from an object, that object is automatically passed to the extension method in that parameter.
This ToggleCustomerStatus method, for instance, will appear in the IntelliSense list of any Customer object (or any object that inherits from Customer) and, unlike my previous example, doesn't return a value:
Public Module CustomerExtensions
  
  Public Sub ToggleCustomerStatus(ByVal cust As Customer)
    cust.Status = Not cust.Status
  End Sub
End Module
To use the extension method, you need to add an Imports or using statement for the namespace that the extension was declared in. If the extension method is in the same namespace as the object it's attaching itself to, developers using that object will probably already have that namespace in place. After that, using an extension method looks just like using any other method (and it doesn't matter if the class the extension method is being attached to is written in one language and the extension method itself is written in another language). Here's the C# ToggleCustomerStatus method in action in some VB code:
Dim cust As Customer
If cust.ToggleCustomerStatus Then …
And the VB version used from C# code:
Customer cust;
cust.ToggleCustomerStatus();
While my sample extension method accepts only the single parameter that specifies which class it should attach itself to, an extension method can accept multiple parameters, just like any other method. You can also specify an interface as the first parameter's datatype so that your extension method will attach itself to a variety of objects (provided they all implement that interface). And, most importantly, you don't change any working code.

No comments:

Post a Comment

Could not find a part of the path ... bin\roslyn\csc.exe

I am trying to run an ASP.NET MVC (model-view-controller) project retrieved from TFS (Team Foundation Server) source control. I have added a...