Extension methods do not provide something that can't be done in other ways. They are syntactical sugar to make development nicer, without providing an actual technical benefit.
Extension methods are relatively new. Standards and conventions are usually decided by popular opinion (plus some long term experience on what ends up being a bad idea), and I don't think we're at the point where we can draw a definitive line that everyone agrees with.
However, I can see several arguments, based on things I've heard from coworkers.
1. They are usually replacing static methods.
Extension methods are most commonly based on things that would otherwise have been static methods, not class methods. They look like class methods, but they aren't really.
Extension methods simply shouldn't be considered an alternative for class methods; but rather as a way to give otherwise syntactically ugle static methods a "class methody" look and feel.
2. When your intended method is specific to a consuming project but not the source library.
Just because you develop both the library and the consumer doesn't mean that you're willing to put the logic wherever it fits.
For example:
- You have a
PersonDto
class coming from your DataLayer
project.
- Your
WebUI
project wants to be able to convert a PersonDto
to a PersonViewModel
.
You can't (and wouldn't want to) add this conversion method to your DataLayer
project. Since this method is scoped to the WebUI
project, it should live inside that project.
An extension method allows you to have this method globally accessible within your project (and possible consumers of your project), without requiring the DataLayer
library to implement it.
3. If you think data classes should only contain data.
For example, your Person
class contains the properties for a person. But you want to be able to have a a few methods that format some of the data:
public class Person
{
//The properties...
public SecurityQuestionAnswers GetSecurityAnswers()
{
return new SecurityQuestionAnswers()
{
MothersMaidenName = this.Mother.MaidenName,
FirstPetsName = this.Pets.OrderbyDescending(x => x.Date).FirstOrDefault()?.Name
};
}
}
I've seen plenty of coworkers who hate the idea of mixing data and logic in a class. I don't quite agree with simple things like formatting data, but I do concede that in the above example, it feels dirty for Person
to have to depend on SecurityQuestionAnswers
.
Putting this method in an extension method prevents sullying the otherwise pure data class.
Note that this argument is one of style. This is similar to partial classes. There is little to no technical benefit to doing so, but it allows you to separate code into multiple files if you deem it cleaner (e.g. if many people use the class but don't care about your additional custom methods).
4. Helper methods
In most projects, I tend to end up with helper classes. These are static classes that usually provide some collection of methods for easy formatting.
E.g. one company I worked at had a particular datetime format they wanted to use. Rather than having to paste the format string all over the place, or make the format string a global variable, I opted for a DateTime extension method:
public static string ToCompanyFormat(this DateTime dt)
{
return dt.ToString("...");
}
Is that better than a normal static helper method? I think so. It cleans up the syntax. Instead of
DateTimeHelper.ToCompanyFormat(myObj.CreatedOn);
I could do:
myObj.CreatedOn.ToCompanyFormat();
This is similar to a fluent version of the same syntax. I like it more, even though there is no technical benefit from having one over the other.
All of these arguments are subjective. None of them cover a case that could otherwise never be covered.
- Every extension method can easily be rewritten to a normal static method.
- Code can be separated in files using partial classes, even if extension methods didn't exist.
But then again, we can take your assertion that they are never necessary to the extreme:
- Why do we need class methods, if we can always make static methods with a name that clearly indicates that it's for a particular class?
The answer to this question, and yours, remains the same:
- Nicer syntax
- Increased readability and less code pedantry (code will get to the point in less characters)
- Intellisense provides contextually meaningful results (extension methods are only shown on the correct type. Static classes are usable everywhere).
One particular extra mention though:
- Extension methods allow for a method chaining coding style; which has become more popular lately, as opposed to the more vanilla method wrapping syntax. Similar syntactical preferences can be seen in LINQ's method syntax.
- While method chaining can be done by using class methods as well; keep in mind that this doesn't quite apply to static methods. Extension methods are most commonly based on things that would otherwise have been static methods, not class methods.