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.