The point of extension methods is to allow you to add features to classes you cannot modify or inherit from. For example, if in a very specific case you want to display an integer as a money,
- either you create a static class
HelloWorld
with the method public static string DisplayIntAsMoney(int amount)
and use it like HelloWorld.DisplayIntAsMoney(5990)
to obtain "$US 59.90",
- or you create an extension method and use it like
5990.AsMoney()
.
The first one is ugly. The second one is ugly too, but much shorter.
But extension methods don't have to be used everywhere to do everything. This is a tool. Don't use it abusively.
For example, if you've written a library with a class and you want to add features to it to use in another project, you have two choices:
The first one is ugly. Very ugly. It also forces you to violate the DRY principle, since you'll probably rewrite the same extension method again and again in many projects which will use the same library. The second one on the other hand let you provide more features without breaking backward compatibility (at least in the case you create an inherited class).
This being said, extension methods are pretty useful in two cases:
When you need to extend classes you cannot modify,
When you need to provide common features without having to modify the existing huge codebase or you have to provide features that may be turned on and off by adding or removing references to your project.
The first reason doesn't apply to .NET BCL. Microsoft has the source code. Microsoft can modify it directly, instead of using extension methods. It's exactly what happens actually.
The second reason applies to .NET codebase. But, wait, aren't they doing exactly this thing with LINQ, Reactive Extensions, etc.?
Edit following your comment:
There are four reasons why we have Math.Round(a)
instead of a.Round()
:
Math.Round
existed before extension methods appeared, and it's never a good idea to rewrite an existing API just for the sake of rewriting, breaking all legacy source code.
Having extension methods for Round
or Pow
but static methods for Max
is just too confusing, especially when you don't use the API too often. Actually, I know that if I want something mathematical, I have to type Ma
, autocomplete, and start to type the name of the method. With your approach, I would sometimes mistake by starting to type Ma
, searching for the method, discovering that the method does not exist, recalling that it might be an extension method, removing Math.
then starting to type in a way to obtain autocompletion for the extension method.
Math
methods belong to System
namespace. This namespace is declared in nearly every file of every project. This would mean that you'll have Round
, Floor
etc. autocompletion every time you enter an integer followed by a dot. It's just too annoying. Having too many methods in intellisense not only makes it difficult to find the good one, but it also decreases performance on slow computers.
float
, double
and int
do not inherit from the same type. If LINQ extension methods are commonly associated with IEnumerable
or some base types, it is impossible to do it with Math
methods. The only way is to write code for every type, which is probably not the most elegant approach. With static methods, there are also overloads, but they are much shorter to write and easier to understand.