9

I've recently been toying with the idea of using extension methods to implement helper utilities on classes which I control (ie, are in the same program and I can modify). The rationale behind it is that many times, these helper utilities are used in very specific scenarios and don't require access to the classes internal values.

For instance, let's say I have a StackExchange class. It'd have methods like PostQuestion and Search and AnswerQuestion.

Now, what if I wanted to manually calculate my reputation to ensure that StackOverflow isn't cheating me. I'd implement something along the lines of:

int rep=0;
foreach(var post in StackExchangeInstance.MyPosts)
{
  rep+=post.RepEarned;
}

I could add a method to the StackExchange class, but it doesn't require any internals, and it is only used from one or two other portions of the program.

Now imagine if instead you had 10 or 20 of these specific helper methods. Useful in a certain scenario for sure, but definitely not for the general case. My idea is changing something like

public static RepCalcHelpers
{
  public static int CalcRep(StackExchange inst){ ... }
}

To something like

namespace Mynamespace.Extensions.RepCalculations
{
  public static RepCalcExtensions
  {
    public static int CalcRep(this Stackexchange inst){...}
  }
}

Note the namespace. I'd ideally use this to group extension methods within a certain scenario. For instance, "RepCalculations", "Statistics", etc.

I've tried searching for if this type of pattern is at all heard of, and haven't found any evidence of extension methods being used for anything but classes you can't modify.

What shortcomings are there with this "pattern"? Should I instead stick to inheritance or composition, or just a good ol' static helper class for this?

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • Extensions method are meant to be used when you can't modify the original class. If you're the one implementing the class, then I fail to see the added value. If you just want to put the methods in a separate code file, you can use the `partial` keyword. – Kevin Gosse Dec 28 '12 at 17:02
  • Just to clarify, you would do this so you could hide certain functions by not including the specific `using` statements that hold the edge-case extension methods?? Very interesting! – Michael Bray Dec 28 '12 at 17:03
  • You can check [this](http://stackoverflow.com/a/551600/649524) link that specifies pros/cons of extension methods – Tilak Dec 28 '12 at 17:03
  • 4
    @KooKiz the point behind it is so that you don't get what I like to call "Telerik Syndrome" where there are over 100 public elements to a class, which makes using intellisense next to useless for "discovering" a class. – Earlz Dec 28 '12 at 17:04
  • Personally (!) I dont see anything wrong with your idea. I just hate to have intellisense offering me a list of 500 methods that a specific class has. "Turning on and off" unneeded features would help much in some cases. – igrimpe Dec 28 '12 at 17:05

4 Answers4

4

I would read the section of Framework Design Guidelines on Extension methods. Here is a post by one of the authors for the 2nd edition. The use case you are describing (specialized helper methods) is cited by Phil Haack as a valid use for extension methods with the drawback that it requires extra knowledge of the API to find those "hidden" methods.

Not mentioned in that post but recommended in the book is that the extension methods go into a separate namespace from the extended class. Otherwise, they will always appear with intellisense and there is no way to turn them off.

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • Well, consistency I assume is your friend for keeping them discoverable. Having a common `.Extensions.*` namespace I assume would keep this fairly easy – Earlz Dec 28 '12 at 17:07
  • @Earlz Consistency is definitely a plus. I'd weigh that against having to add many `using` statements to do anything useful. – Mike Zboray Dec 28 '12 at 17:17
  • Well, ideally you'd never want to add more than 2 extension using statements, so it'd be difficult to balance just how coarsely the extensions are grouped – Earlz Dec 28 '12 at 17:23
0

I think I have seen this pattern somewhere else. It could quite confusing, but also quite powerful. That way you can provide a class in a library and a set of extension methods in separate namespace. Then whoever is using your library can choose to import namespace with your extension methods or provide their own extension methods.

A good candidate for this pattern would be if you have some extension methods used for unit testing only (e.g. to compare if two objects are equal in a sense you'd need for unit tests only).

Sebastian K
  • 6,235
  • 1
  • 43
  • 67
0

You seem to be making the comparison that the extension method is equivalent to a public instance method. It's really not.

An extension method is just a public static utility method that happens to have a more convenient syntax for being called.

So first we have to ask ourselves, it it appropriate for this method to be an instance method of the class itself or is it more appropriate for it to be a static method of an external class. The fact that very few users of the class need this functionality because it's highly localized and not truly behavior that the class itself performs but rather behavior performed on the class by an external entity means that it's appropriate for it to be static. The primary drawback is that it's behavior that is potentially harder to find if someone has a User and wants to recalculate their rep. Now, in this particular case it's a bit on the fence, and you could go the other way, but I am leaning towards static method.

Now that we've decided it should be static it's an entirely separate question of whether or not it should be an extension method or not. This is much more subjective and goes into the personal preference realm. Are the methods likely to be chained? If so, extension methods chain much more nicely than nested calls to static methods. Is it likely to be used a lot in the files that do use it? If yes, extension methods are likely going to simplify the code a bit, if not, it doesn't really help as much, or even hurts. To the toy example I'd probably say that I personally wouldn't, but I wouldn't have any problem at all with someone who did (after all you can still use an extension method as if it's a regular public static method syntax wise). For a non-toy example, it's mostly a case-by-case decision. A key point is to be careful what classes you extend, and to ask yourself if a user is willing to clutter the Intellisense of a type just to call a methods slightly more conveniently (this again gets back to how much it's used per file it's used in).

It's also worth mentioning that there are a few edge cases where extension methods can be more powerful than instanced methods. In particular through utilizing type inference. With a regular instance method it's easy enough to accept a type or any sub-type of that type, but sometimes it's useful to return whatever the type is that was passed in instead of the parent type. This is used particularly in fluent APIs. This isn't a very common example though, and is only loosely related to your question, so I won't expand on that.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • For the whole static method versus extension bit: For this particular case, I actually think extension methods are more discoverable, assuming you use intellisense. You'd first look in the Extensions namespace for something relevant to what you're doing and then methods you want are just automatically in the applicable class. I can't tell you how many times I've had to look for static helper classes, especially when they are in different inconsistent namespaces – Earlz Dec 28 '12 at 17:21
0

Extension methods could be very useful in cases where you class implements an interface and you want to avoid having to implement the same method on other "future" classes that implement the same interface. For example, StackExchange implements IStackExchange and ProgrammersExchange also implements IStackExchange. Your example extension method would be useful for implementing the CalcRep just once, and not having to re-implement it on both classes. This is exactly the reason for all the extension methods present in the static Enumerable class.

Other than this I dont see a compelling reason for using extension methods on a class you can already modify. If anything it has the disadvantage of being considered late in the overload resolution process.

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • I don't actually think a helper utility being considered late for overloads is a bad thing, in most cases. Look a Linq, sure there is an `IEnumerable.Count()` extension method, but many things which implement IEnumerable have much faster ways of counting than iterating over the whole list – Earlz Dec 28 '12 at 17:29
  • The Enumerable.Count method is well suited to be an extension method for the reason I mentioned initially, not so that it is late in the overload resolution. Even if it were part of the interface, each implementer could implement their own fast method of counting. – Eren Ersönmez Dec 28 '12 at 17:40
  • 1
    ... And in fact, the Count() LINQ method as currently implemented makes some type checks, and will defer to ICollection.Count if the source enumerable is an ICollection. The method that takes a predicate does not make this check, however, and any use of Count() on the end of an additional Linq extension will be passed an IEnumerable that is not an ICollection. – KeithS Dec 28 '12 at 17:57