3

Why I Don't Like C# Extension Methods - DaedTech

 1 year ago
source link: https://daedtech.com/why-i-dont-like-c-extension-methods/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Why I Don’t Like C# Extension Methods

Category: .NET

Tags: C#

When I first became aware of the Extension Method in C#, my reaction was similar to that of a lot of people–I thought it was a pretty neat trick. For anyone not familiar with extension methods, they are a construct introduced in C# along with LINQ to allow ‘extension’ of a class. Here’s an example:

public static class Extensions
{
    public static string GetWordCount(this string str)
    {
        return str.Split(' ').Length;
    }
}

//Client code looks like:
public void SomeMethod(string str)
{
    if(str.GetWordCount() > 1)
    {
        //Do multiple word stuff
    }
    else
    {
        /Do single word stuff
    }
}

What’s going on behind the scenes here is that Microsoft introduced syntactic sugar on standard static methods. An extension method is really just a static method, and as far as the compiler is concerned, the client code is no different than it would be if you called “Extensions.GetWordCount(str);”

The advantages are immediately obvious. You can abstract verbose and redundant common idioms into these methods, favoring instead descriptive terminology. You can make it look as though GetWordCount() is a method of string, even though it isn’t. This means that, done right, you can create the appearance of enhanced classes without modifying the classes themselves. If you keep these methods well organized, they seem a natural enhancement to the language. And perhaps the most powerful thing of all is that you can extend library classes that are sealed or have non-virtual methods, or you can supply enhancements to your own API for others without the risk of introducing breaking changes.

But in spite of those benefits, something bothered me about this idea. I couldn’t quite put my finger on it for a long time. The drawbacks that one that might see in a google search or realize on his own include decoupling class-specific functionality from that class (i.e. violating encapsulation) and the fact that you’re favoring free-floating static utility over instance methods. There is also the possibility for naming collisions if you write an extension method with the same signature as an instance method. There is the confusion that one might experience not knowing through intellisense whether you were dealing with a native method of some class or an afterthought that somebody tacked on. But all of those drawbacks seemed to have reasonable counterpoints, and none of them really address the notion of enhancing bad APIs that you’ve been given or putting out your own extensions to preserve reverse compatibility.

So, as an experiment, I developed a little utility and decided to load up on extension methods to really try them out, having previously only been a client of them. I was writing a bunch of things out to an HTML file and using the XDocument API to do it (taking advantage of the fact that HTML is conceptually a subset of XML), so I thought I had the perfect opportunity. I added a bunch of extension methods for XElement that would do things like create tables, styles, and other HTML constructs. I would do something like myXElement.CreateTableOutline(rows, columns, title, headerColor);

It was pretty slick. And, as I did it, I found that these extension methods begat more extension methods for other things. Pretty soon, I had the cleanest, easiest to read code that you could ever want in a data access object. It read like a book, not like code: “Element.CreateTableWithThis()”, and, “Element.PopulateTableWithThat();” Best of all, it looked like a beautiful object-oriented design.

And, at that moment, the thing I couldn’t put my finger on that had been bothering me leaped into full view. It looked like object-oriented design. Extension methods, as I mentioned earlier, are just stateless (hopefully) static methods gussied up to look like instance methods. And, stateless static methods are really just procedural constructs that exist outside of any application state at all–the much younger brother with a striking resemblance to something in the C world that you might call “utils.c” and populate with 8000 functions that just didn’t fit anywhere else.

The whole time, I had been making my code increasingly procedural. I had been moving ugly functionality out of my instances and putting it into the blob of stateless static functionality, prettying it up by making it a series of extension methods. Rather than create some kind of HtmlElement class that inherited from or wrapped an XElement, I created a laundry list of extension methods that could easily have been called “public static class HtmlUtils”. Taken to its logical conclusion, I could write an entirely procedural application with nothing but extensions of existing classes. I realize that nobody is likely to do that, but it is interesting that such a thing is possible and that you can gravitate toward it without realizing it.

And that is the crux of what bothered me all along. Here, we have a brand, spankin’ new language feature introduced to an object-oriented language that gives users the ability to make their code substantially more procedural while making it look substantially more like a clean object-oriented design. Extension methods are the ultimate in deodorant for a code smell. If you venture down that rabbit hole, you’ll never ask yourself why you’re increasingly favoring static utils methods instead of object-oriented design because you will fool everyone else and even yourself into thinking that you are using object-oriented principles.

The denouement of my little story was that I systematically removed all of the extension methods. In their place, I created a series of small methods on a common base class and factored some of the functionality into value objects and small inheritance structures that defined HTML constructs. The result wasn’t as pretty, and I didn’t get the fluent interface feel, but the way I see it, I gave up high fructose corn syrup for fresh-squeezed orange juice. The new design may have required that I add a few classes, but I now have the ability to extend CreateTable() in sub-classes rather than adding a bunch of additional static methods for that functionality. With stateless static methods, you can’t inherit base classes or implement interfaces to take advantage of polymorphism.

I’m not advocating that everybody swear off extension methods (or really advocating much of anything), but rather explaining why I don’t like the construct and choose not to use it. Since my discovery, I’ve paid closer attention to how other people use extension methods. I’ve seen them used to circumvent the compiler for preventing circular dependencies. I’ve seen them used to ‘extend’ functionality in the same namespace where it would have been perfectly reasonable just to add a method to the class itself. I’ve even seen them used to hold and alter global state. And I’ve also seen them used somewhat reasonably.

But, at the end of the day, extension methods are the cousin of the singleton in that they both have an unanticipated side effect. That side effect is a vehicle for developers who are forced to develop in OO languages, but have always carried the torch for procedural programming, to sneak back to visit the ex without anyone knowing. In both cases, for the OO programmer, I would advise a bit of frank examination of the motivations for using the construct. Is it because extending the class (or forcing one global instance) is the only/best possible approach, or is it because it’s easier and faster than taking a hard look at your design or object graph? If it’s the latter, you could be heading for some headaches down the road.

By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK