415

ReSharper likes to point out multiple functions per ASP.NET page that could be made static. Does it help me if I do make them static? Should I make them static and move them to a utility class?

Pang
  • 9,564
  • 146
  • 81
  • 122
dlamblin
  • 43,965
  • 20
  • 101
  • 140
  • 22
    Isn't Resharper actually shouting "low-cohesion, low-cohesion"? it is time to look if the method really belongs to that class. – P.K Dec 26 '10 at 02:34
  • 2
    possible duplicate of [Advantages to Using Private Static Methods](http://stackoverflow.com/questions/135020/advantages-to-using-private-static-methods) – drzaus Aug 06 '15 at 17:02

14 Answers14

292

Performance, namespace pollution etc are all secondary in my view. Ask yourself what is logical. Is the method logically operating on an instance of the type, or is it related to the type itself? If it's the latter, make it a static method. Only move it into a utility class if it's related to a type which isn't under your control.

Sometimes there are methods which logically act on an instance but don't happen to use any of the instance's state yet. For instance, if you were building a file system and you'd got the concept of a directory, but you hadn't implemented it yet, you could write a property returning the kind of the file system object, and it would always be just "file" - but it's logically related to the instance, and so should be an instance method. This is also important if you want to make the method virtual - your particular implementation may need no state, but derived classes might. (For instance, asking a collection whether or not it's read-only - you may not have implemented a read-only form of that collection yet, but it's clearly a property of the collection itself, not the type.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I would think a good linter should have an option to restrict the message to non-virtual methods, since it would be very common for a base-class method to do practically nothing. Override methods would usually do something, but not always. Sometimes it's useful to have a class for something like an empty iEnumerable, whose methods essentially ignore the instance, but where the instance is required to select the right method to use. – supercat Jul 13 '10 at 15:11
  • 3
    "Sometimes there are methods which logically act on an instance but don't happen to use any of the instance's state yet. For instance" I enjoyed your use of "for instance" in this instance. – PaulBinder Aug 19 '19 at 21:02
272

Static methods versus Instance methods
Static and instance members of the C# Language Specification explains the difference. Generally, static methods can provide a very small performance enhancement over instance methods, but only in somewhat extreme situations (see this answer for some more details on that).

Rule CA1822 in FxCop or Code Analysis states:

"After [marking members as static], the compiler will emit non-virtual call sites to these members which will prevent a check at runtime for each call that ensures the current object pointer is non-null. This can result in a measurable performance gain for performance-sensitive code. In some cases, the failure to access the current object instance represents a correctness issue."

Utility Class
You shouldn't move them to a utility class unless it makes sense in your design. If the static method relates to a particular type, like a ToRadians(double degrees) method relates to a class representing angles, it makes sense for that method to exist as a static member of that type (note, this is a convoluted example for the purposes of demonstration).

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
  • 2
    > the compiler will emit non-virtual call sites to these members Actually that is "the compiler may emit...". I remember something about the C# compiler using callvirt instead of call to work around some potential bug. – Jonathan Allen Oct 04 '08 at 04:41
  • 27
    I cut and paste it directly from FxCop 1.36. If FxCop is wrong, fair enough. – Jeff Yates Oct 04 '08 at 06:20
  • 9
    @Maxim Not sure I appreciate the "bullshit" statement; pretty rude way to approach strangers. However, the underlying point is valid; I've updated things a bit (it was 9 years ago, so I don't recall the foundation of my original claim). – Jeff Yates Feb 20 '17 at 22:57
  • @JeffYates Man you have a good rating, you cannot write this .... hmm.. wrong claim... many young developers will read it, and maybe they will write software for my Tesla in the future, because there are already such 200 developers ))) But please do not be offended even if I bother you )) – Maxim Feb 20 '17 at 23:54
  • 17
    @Maxim Your point is invalid. I assure you that I did not have a good rating 9 years ago. I appreciate comments that point out mistakes (or edits that correct them), but don't be rude nor put unreasonable expectations on others. Don't call something "bullshit"; it implies an intent to deceive rather than honest to goodness mistake or ignorance. It's rude. I volunteer my time to help here and it really feels pointless when it is treated with disrespect. Do not tell me what to be offended by - that's my choice, not yours. Learn how to make your point with respect and integrity. Thank you. – Jeff Yates Feb 21 '17 at 00:54
  • 2
    @Maxim While delegates aren't stored alongside each instance, each instance of a stateless class does indeed occupy some memory on the heap, which is useless overhead. Usually instantiating services is not the hot path in an application, but if your application ends up constructing a lot of these objects it is going build up GC pressure that could be avoided by simply using static methods. The OP's original claim, that in extreme situations static methods provide a performance benefit over stateless instances, was appropriately nuanced and valid. – Asad Saeeduddin Apr 25 '17 at 19:19
  • @AsadSaeeduddin It is totally invalid! First of all do not mess instance memory allocation and memory for instance method. You do not need 1mln of instances to call some instance method 1mln times. If you need 1 mln instances then it is for storing some data. It is not related to memory for instance method. Static method and instance method implementations are stored once and referenced in method table. So each new instance of class containing some instance method will not require additional memory for instance method! What was confirmed by me during measuring of size of all heaps of process. – Maxim Apr 27 '17 at 01:44
  • 1
    @Maxim When things are being injected into your controllers, how many instances are created is not up to you. Every instance is useless overhead if it is stateless and Resharper is able to suggest replacing it with a static method. Regarding: "So each new instance of class containing some instance method will not require additional memory **for instance method!**". This is not the same as saying it will not require additional memory. – Asad Saeeduddin Apr 27 '17 at 02:02
  • @AsadSaeeduddin You cannot use static methods if something is injected in your controller! But why we are talking about count of instances? Question was Static vs Instance. So we need to just compare: CPU load, memory footprint, best practices. Best practice is not something for discussion here. So memory footprint.. as I said it is THE SAME (small difference of compiled representation does not matter), CPU load: for static it is better a bit due to passing this implicitly and skipping virtual lookup (only in comparison with virtual instance methods). And this mostly considered in Jeff update. – Maxim Apr 27 '17 at 02:52
  • 1
    @Maxim "You cannot use static methods if something is injected in your controller" This is incorrect. Any stateless injected service can be substituted with static methods. That's the last I'll say about it in this thread, feel free to open a chat room if you still don't understand. – Asad Saeeduddin Apr 27 '17 at 02:56
  • 1
    @Maxim I suspect there might be a language barrier at work here. The OP is asking whether they should replace instance methods that Resharper is able to recognize as independent of the class state with static methods. In order to use instance methods, you need to have an instance of a class, and instantiating a class has memory and runtime overhead. If you instead substitute ("substitute" is an English word meaning "replace") the instance methods with static methods, you can simply invoke the method without paying the cost of creating an instance. – Asad Saeeduddin Apr 28 '17 at 12:21
  • @AsadSaeeduddin OK, I just told all above in context of "Static methods versus Instance methods"... as it is (from point of view of the runtime).. no in context of original question and any specific logic workflow.. – Maxim Apr 29 '17 at 12:35
64

Marking a method as static within a class makes it obvious that it doesn't use any instance members, which can be helpful to know when skimming through the code.

You don't necessarily have to move it to another class unless it's meant to be shared by another class that's just as closely associated, concept-wise.

Ben
  • 54,723
  • 49
  • 178
  • 224
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
22

I'm sure this isn't happening in your case, but one "bad smell" I've seen in some code I've had to suffer through maintaining used a heck of a lot of static methods.

Unfortunately, they were static methods that assumed a particular application state. (why sure, we'll only have one user per application! Why not have the User class keep track of that in static variables?) They were glorified ways of accessing global variables. They also had static constructors (!), which are almost always a bad idea. (I know there are a couple of reasonable exceptions).

However, static methods are quite useful when they factor out domain-logic that doesn't actually depend on the state of an instance of the object. They can make your code a lot more readable.

Just be sure you're putting them in the right place. Are the static methods intrusively manipulating the internal state of other objects? Can a good case be made that their behavior belongs to one of those classes instead? If you're not separating concerns properly, you may be in for headaches later.

JasonTrue
  • 19,244
  • 4
  • 34
  • 61
14

This is interesting read:
http://thecuttingledge.com/?p=57

ReSharper isn’t actually suggesting you make your method static. You should ask yourself why that method is in that class as opposed to, say, one of the classes that shows up in its signature...

but here is what ReSharper documentaion says: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

Pang
  • 9,564
  • 146
  • 81
  • 122
pajics
  • 2,938
  • 3
  • 23
  • 27
  • 2
    I think this point is underrated. What the tool is really telling you is that the method only operates on some other class's members. If it's some kind of command (or "use case" or "interactor") object, who's responsibility is to manipulate other objects, that's fine. However, if it only manipulates a single other class that sounds a lot like [Feature Envy](http://wiki.c2.com/?FeatureEnvySmell). – Greg May 19 '17 at 18:57
  • 1
    First link in answer is dead. – Pang Mar 25 '21 at 06:18
10

Just to add to @Jason True's answer, it is important to realise that just putting 'static' on a method doesn't guarantee that the method will be 'pure'. It will be stateless with regard to the class in which it is declared, but it may well access other 'static' objects which have state (application configuration etc.), this may not always be a bad thing, but one of the reasons that I personally tend to prefer static methods when I can is that if they are pure, you can test and reason about them in isolation, without having to worry about the surrounding state.

Community
  • 1
  • 1
Benjol
  • 63,995
  • 54
  • 186
  • 268
8

For complex logic within a class, I have found private static methods useful in creating isolated logic, in which the instance inputs are clearly defined in the method signature and no instance side-effects can occur. All outputs must be via return value or out/ref parameters. Breaking down complex logic into side-effect-free code blocks can improve the code's readability and the development team's confidence in it.

On the other hand it can lead to a class polluted by a proliferation of utility methods. As usual, logical naming, documentation, and consistent application of team coding conventions can alleviate this.

G-Wiz
  • 7,370
  • 1
  • 36
  • 47
6

You should do what is most readable and intuitive in a given scenario.

The performance argument is not a good one except in the most extreme situations as the only thing that is actually happening is that one extra parameter (this) is getting pushed onto the stack for instance methods.

Eric Schoonover
  • 47,184
  • 49
  • 157
  • 202
5

ReSharper does not check the logic. It only checks whether the method uses instance members. If the method is private and only called by (maybe just one) instance methods this is a sign to let it an instance method.

brgerner
  • 4,287
  • 4
  • 23
  • 38
4

I hope you have already understood the difference between static and instance methods. Also, there can be a long answer and a short one. Long answers are already provided by others.

My short answer: Yes, you can convert them to static methods as ReSharper suggests. There is no harm in doing so. Rather, by making the method static, you are actually guarding the method so that you do not unnecessarily slip any instance members into that method. In that way, you can achieve an OOP principle "Minimize the accessibility of classes and members".

When ReSharper is suggesting that an instance method can be converted to a static one, it is actually telling you, "Why the .. this method is sitting in this class but it is not actually using any of its states?" So, it gives you food for thought. Then, it is you who can realize the need for moving that method to a static utility class or not. According to the SOLID principles, a class should have only one core responsibility. So, you can do a better cleanup of your classes in that way. Sometimes, you do need some helper methods even in your instance class. If that is the case, you may keep them within a #region helper.

Pang
  • 9,564
  • 146
  • 81
  • 122
Emran Hussain
  • 11,551
  • 5
  • 41
  • 48
3

If the functions are shared across many pages, you could also put them in a base page class, and then have all asp.net pages using that functionality inherit from it (and the functions could still be static as well).

Mun
  • 14,098
  • 11
  • 59
  • 83
3

Making a method static means you can call the method from outside the class without first creating an instance of that class. This is helpful when working with third-party vendor objects or add-ons. Imagine if you had to first create a Console object "con" before calling con.Writeline();

Austin
  • 31
  • 2
2

It helps to control namespace pollution.

Josh
  • 7,936
  • 5
  • 41
  • 63
  • 10
    How does making a method static help avoid namespace pollution? – lockstock Apr 07 '14 at 04:46
  • 1
    From experience, by grouping methods into classes with static methods, you're avoiding the experience of having to prefix all of the "grab bag" of loose functions that may conflict with other library or built-in functions. With static methods, they're effectively namespaced under the Classname, ex. `Class.a_core_function( .. )` vs `a_core_function( .. )` – lintuxvi Dec 08 '16 at 20:15
0

Just my tuppence: Adding all of the shared static methods to a utility class allows you to add

using static className; 

to your using statements, which makes the code faster to type and easier to read. For example, I have a large number of what would be called "global variables" in some code I inherited. Rather than make global variables in a class that was an instance class, I set them all as static properties of a global class. It does the job, if messily, and I can just reference the properties by name because I have the static namespace already referenced.

I have no idea if this is good practice or not. I have so much to learn about C# 4/5 and so much legacy code to refactor that I am just trying to let the Roselyn tips guide me.

Joey

Joseph Morgan
  • 163
  • 1
  • 9