Best Practice for Static vs. Instance Methods when Values are Required

2.6k views Asked by At

I've read about static vs. instance methods here, but I don't see any that answer this particular question (green as it may be).

When you have a class with some properties, and a method in that class that needs to use those properties, is it better to do it with a static or an instance method?

I.E.

class Foo
{
    //properties
    bar1;
    bar2;

    //method
    sumbar1andbar2()
    {
        return bar1 + bar2;
    }
}

The sumbar1andbar2 method needs both the properties of the Foo class to be present. It seems a bit goofy to make a static method and call it this way, since I'm manually passing the members of the class into the class's method:

Foo foo1 = new Foo();
foo1.bar1 = x;
foo1.bar2 = y;
sumbar1andbar2(foo1.bar1, foo1.bar2); 

But although the instance method below seems much cleaner, I'm not aware of a clean and easy way to ensure that both bar1 and bar2 are not null, which would cause an exception:

Foo foo1 = new Foo();
foo1.bar1 = x;
foo1.bar2 = y;
sumbar1andbar2();

However, the instance method seems even better if the method modifies another property of the class, like bar3.

3

There are 3 answers

1
Sergey Kalinichenko On BEST ANSWER

First, there is a nice and easy way to ensure that your properties are not null: it is called encapsulation. Make sure the properties are set in the constructor, and do validation in their setter if you choose to expose one. This way the properties will be non-null after the object is constructed (otherwise, constructor would throw an exception), and the property setters would leave property values in a consistent state (otherwise, setters would throw an exception).

Now to the actual question: if one or both values could potentially be coming from other instances of Foo, make the calculating method static. Otherwise, make it an instance method.

P.S. If your method returns a value, does not have parameters, and does not produce side effects, consider making it a calculated property instead of a method.

2
Chris Shain On

If the method's behavior is unique to the type Foo (and not meaningfully applicable elsewhere), or if it modifies Foo's state, then you should probably make it an instance method of Foo.

If it is a generic calculation (like your example) where you might want to use it elsewhere, you have a few options:

Make it a static method on a utility class, e.g.

public static class MyUtility {
    public static Int32 Add(Int32 x, Int32 y) { return x + y; }
}

Make it an extension method on Foo, it's parent class, or an interface that defines x and y, e.g.

// Use as follows:
// var f = new Foo() { x = 5, y = 5 };
// var ten = f.MyUtility();
public static class MyUtility {
    public static Int32 Add(this Foo foo) { return Foo.x + Foo.y; }
}
0
Jon Hanna On

If it relates to a particular instance, then it must be an instance member (whether method, property or field). These are the most common cases, so examples are plentiful.

If it doesn't relate to a particular instance, then an instance member requires an instance that you won't use in any other way. A good example is Math.Max, if you call Math.Max(43, 23) then the result relates to the fact that 43 is greater than 23, not to any property of a Math object that could conceivably change over the course of an application's running.

Some classes only have need for static members, so we make the class itself static and it can't be instantiated at all.

Propeties that relate to the nature of the class rather than a given instance should also be static for the same reason. E.g. int.MaxValue is a property of int, not of e.g. 93.

Note that the result of int.MaxValue is itself an int. This is not uncommon. Other examples include TimeSpan.Zero and string.Empty. This can be a convenience and also sometimes a performance benefit in preventing lots of duplicate reference types (irrelevant in the case of value types, and not to be over-stated in the case of reference types). It's important not to over do this. We wouldn't want 4294967296 different static properties on int to make it "easy" to call them! Generally this is useful either when:

The special case can't be constructed by a constructor.

OR:

The special case is commonly used (TimeSpan.Zero) and/or inconvenient to remember (int.MaxValue is clearer and easier to recall than 2147483647 or even 0x7FFFFFFF). All the more so if it's both of course.

Extension methods are static methods that can be called as if they were instance members. They're very convenient, but it's generally better to use an instance member when you can. They're useful when an instance member is impossible, because:

  1. You don't have access to the source of the class (it's another party's class).
  2. You want to define it on an interface rather than a class.
  3. You want it to be callable on null (avoid, this is non-idiomatic in C# though more common in other languages).
  4. You want to define it for particular cases of generics. For example, if I created MyDictionary<TKey, TValue> that implemented IDictionary<TKey, TValue> I can't define a plus method that adds a number to a stored value because that can only work when TValue is a known numeric type. I can define such a method as an extension method like int Plus<TKey>(this MyDictionary<TKey, int> dict, int addend) that will then appear like an instance member when TValue is int, but won't interfer with the use of MyDictionary for other type parameters.

All of these cases give you no choice but to use an extension method, but don't use them when an instance member will do the job. It's clearer, especially since some other .NET languages will only see an extension member as a static.