With the advent of extension methods, are abstract classes less attractive?

I do like extension methods because it has given me the ability to define Find(Predicate), Remove(Predicate) etc on IList<T> which I have been missing. I do not think you can say they are a replacement for abstract classes.

I have also defined extension methods to add generic behavior. I love my ToJson extension method on object or ToXml quite handy.

The only problem I have with your example is I always look IsCurrentUser as a property not a method and alas we have no extension properties. But I'm nitpicking

They are completly unrelated. I use an abstract class when I want to model a behavior, that others will implement or inherit.


No, it will reduce some missuses of abstract classes.

An abstract class should contain default implementations/behaviors the subclasses can override. If factored appropriately, this means you could override just a single behavior of the class, and work with the defaults for the rest. Extension methods provide something really different to this.


I have used this functionality several times - and in fact, this functionality was created specifically for the purpose of decorating interfaces without modifying them, hence LINQ. All the goodness that is LINQ (to Objects at least) is based on extension methods to IEnumerable<T>.

However, I don't feel that extension methods in any way replace abstract base classes for when you need them. Extension methods cannot access the extended class's private state - extension methods look like instances, but are still static.

Extension methods and abstract base classes solve two different types of problems, and the choice to use either of these paradigms should not depend on each other.

My answer to your title question is thus: No, the existence of Extension Methods do not make Abstract Base Classes less attractive. If one believes that the existence of Extension Methods makes Abstract Base Classes less attractive, then one wasn't using Abstract Base Classes correctly in the first place.


What extension methods lets you do is to focus in on what abstract classes should actually be doing. There's a temptation to implement "utility" code in abstract classes because it will be used by implementers even though it may not be part of the logical inheritance tree. Extension methods let you attach these utility methods to the interface without cluttering up your abstract base classes.

EDIT

Specifically, I would apply these guidelines.

Inheritance

  • DO use inheritance if the behavior is part of the logical behavior of the base class
  • DO NOT use inheritance if the behavior is cross-cutting (applies to things outside of your object hierarchy). These will require duplication.

Utility Classes

  • DO use utility classes (static classes) if the behavior does not logically belong to the class it's acting on
  • DO NOT use utility classes if they modify the internal state of the object it's acting on. State modification should be reserved only for the object implementation hierarchy.

Extension Methods

  • DO use the same decision for extension methods as you would for utility classes when they create less friction. If adopting extension methods feels less natural, don't do it.
  • DO use extension methods to add utility to classes you don't have control over (like string).
  • DO NOT use extension methods when the behavior is consumed by the class it is extending. While it is possible to do it, it feels contrived
  • DO NOT use extension methods just because you can. In fact don't deviate from good old fashioned OOP unless you have to. When you have to, however, extension methods are a relatively uesful and harmless decision to make.

EDIT 2

Thought of another DO for extension methods

DO use extension methods to provide a natural language (internal DSL) for certain implementations. Here's a silly example.

int age = getAge();
if (age.IsDraftAge() && !age.IsLegalDrinkingAge())
{
    Console.WriteLine(@"You cannot drink until your birthdate on {0}.
Join the army instead.",
                      age.GetYearWhenGettingDrunkIsOk());
}