Extension Methods vs Instance Methods vs Static Class

johnnyRose picture johnnyRose · May 29, 2015 · Viewed 9k times · Source

I'm a little bit confused about the different ways to use methods to interact with objects in C#, particularly the major design differences and consequences between the following:

  1. Invoking an instance method
  2. Using a static class on a POCO
  3. Creating an extension method

Example:

public class MyPoint
{
    public double x { get; set; }
    public double y { get; set; }

    public double? DistanceFrom(MyPoint p)
    {
        if (p != null)
        {
            return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));
        }
        return null;
    }
}

If you could accomplish the desired outcome by simply placing a method in a class definition, why would a POCO combined with either a static helper class or an extension method be preferable?

Answer

Colin picture Colin · May 29, 2015

You asked, "If you could accomplish the desired outcome by simply placing a method in a class definition, why would a POCO combined with either a static helper class or an extension method be preferable?"

The answer is that it depends on the situation, and if the methods in question are directly related to your class' primary concern (see single responsibility principle).

Here are some examples of where it might be a good idea to use each type of approach/method (using your code sample as a starting point).

1. Instance Methods

//This all makes sense as instance methods because you're 
//encapsulating logic MyPoint is concerned with.
public class MyPoint
{
    public double x { get; set; }
    public double y { get; set; }

    public double? DistanceFrom(MyPoint p)
    {
        if (p != null)
            return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));            
        return null;
    }
}

2. Static Class Methods - An error logging example.

    //Your class doesn't directly concern itself with logging implmentation;
    //that's something that is better left to a separate class, perhaps
    //a "Logger" utility class with static methods that are available to your class.
    public double? DistanceFrom(MyPoint p)
    {
        try
        {
            if (p != null)
                return  Math.Sqrt(Math.Pow(this.x - p.x, 2) + Math.Pow(this.y - p.y, 2));            
            return null;
        }
        catch(Exception ex)
        {
             //**** Static helper class that can be called from other classes ****
             Logger.LogError(ex);

             //NOTE: Logger might encapsulate other logging methods like...
             //Logger.LogInformation(string s)
             //...so an extension method would be less natural, since Logger
             //doesn't relate to a specific base type that you can create an
             //extension method for.
        }
}

3. Extension Methods - An XML serialization example.

//Maybe you want to make it so that any object can XML serialize itself
//using an easy-to-use, shared syntax.
//Your MyPoint class isn't directly concerned about XML serialization,
//so it doesn't make sense to implement this as an instance method but
//MyPoint can pick up this capability from this extension method.
public static class XmlSerialization
{
    public static string ToXml(this object valueToSerialize)
    {
        var serializer = new XmlSerializer(valueToSerialize.GetType());
        var sb = new StringBuilder();
        using (var writer = new StringWriter(sb))
            serializer.Serialize(writer, valueToSerialize);

        return sb.ToString();
    }
}

//example usage
var point = new MyPoint();
var pointXml = point.ToXml(); //<- from the extension method

The rule of thumb is:

  1. If the method relates to a class' primary concern, put it in an instance method.
  2. If you have a generic utility that might be useful to multiple classes, consider putting it in a static class' method.
  3. If you have a situation similar to 2, but related to a single base type, or you think the code would look cleaner/more concise without having to separately reference a static class, consider an extension method.