JetBrains Rider 2024.1 Help

Code inspection: Possibly impure struct method is called on readonly variable: struct value always copied before invocation

Consider the following code:

class Test { struct MyStruct { public int Value; public void IncrementValue() { Value +=1; } } readonly MyStruct _readonlyStruct = new MyStruct(); public void RunTest() { // Warning: Impure method is called for readonly field of value type _readonlyStruct.IncrementValue(); Console.WriteLine(_readonlyStruct.Value); // 0 } }

We end up getting 0 in the output, while it might seem that calling IncrementValue() beforehand should make it 1. This happens because when we access a readonly field of a value type, a copy of it is created to prevent the caller from mutating the field.

_readonlyStruct.IncrementValue() in the above example creates a copy of _readonlyStruct, changes its Value field to 1, and then the copy is discarded.

However, we only have this kind of problem with impure methods — methods that change the object state, like IncrementValue() above does. Calling a pure method in a similar situation is not a problem because whether it is called on a copy or not, it doesn't change its state, and we'll get the expected result from the method anyway.

False positives

Unfortunately, JetBrains Rider is not always able to determine whether the method is pure or not, and therefore this inspection sometimes produces false positive warnings, but methods decorated with [Pure] (you can use both JetBrains.Annotations.PureAttribute and System.Diagnostics.Contracts.PureAttribute) are always considered pure and produce no warnings.

Note that a lot of methods in .NET Framework and other frequently used libraries are annotated with [Pure] via external annotations.

Fixing the problem

JetBrains Rider does not offer any quick-fixes for this inspection.

If changing the state of the field is intended in your code, you can make the field mutable by removing the readonly modifier from it.

If you want to keep the field immutable, you should rewrite your code so that an impure method is not invoked on the field.

If the invoked method is pure and the warning is a false positive, then you can either annotate it with [Pure] or suppress this inspection.

Last modified: 11 February 2024