Is using readonly public fields used for immutable structures?

Is this the right way to declare immutable structures?

public struct Pair { public readonly int x; public readonly int y; // Constructor and stuff } 

I can’t think of why this ran into problems, but I just wanted to ask you to make sure.

In this example, I used ints. What if I used a class instead, but this class is also immutable, for example? Should this work fine too?

 public struct Pair { public readonly (immutableClass) x; public readonly (immutableClass) y; // Constructor and stuff } 

(In addition: I understand that using properties is more generalized and allows you to change, but this structure is literally just to store two values. I'm just interested in the issue of immutability here.)

+48
immutability c # struct
May 19 '11 at 18:28
source share
3 answers

If you intend to use structures, it is best to make them immutable.

Creating all readonly fields is a great way to help (1) document that the structure is immutable and (2) prevent accidental mutations.

However, there is one wrinkle that, in a strange coincidence, I was planning to blog about next week. That is: readonly in the struct field is false . You can expect that the readonly field cannot change, but of course it is possible. "readonly" in the struct field is a declaration that writes checks without money in your account. The structure does not have its own repository, and it is a repository that can mutate.

For example, take your structure:

 public struct Pair { public readonly int x; public readonly int y; public Pair(int x, int y) { this.x = x; this.y = y; } public void M(ref Pair p) { int oldX = x; int oldY = y; // Something happens here Debug.Assert(x == oldX); Debug.Assert(y == oldY); } } 

Is there anything that can happen when “something happens here” that breaks debug statements? Sure.

  public void M(ref Pair p) { int oldX = this.x; int oldY = this.y; p = new Pair(0, 0); Debug.Assert(this.x == oldX); Debug.Assert(this.y == oldY); } ... Pair myPair = new Pair(10, 20); myPair.M(ref myPair); 

Now what is happening? Approval violated! "this" and "p" refer to the same storage location. The storage location is mutated, so the contents of "this" are mutated because it is one and the same. The structure cannot provide read-only x and y because the structure does not own the repository; storage is a local variable that can mutate as much as it wants.

You cannot rely on an invariant that is never observed for a readonly field in a structure; the only thing you can rely on is that you cannot write code that directly changes it. But, by stealing this work a little, you can indirectly change everything you want.

See also Joe Duffy's excellent blog article on this issue:

http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/

+101
May 19 '11 at 18:56
source share

That would make him unchanged. I guess you better add a constructor. If all its members are also unchanged, this will make him completely unchanged. These can be classes or simple values.

+5
May 19 '11 at 18:30
source share

The compiler will prevent assignment to readonly fields, as well as read-only properties.

I recommend using read-only properties, mainly for public interfaces and data binding (which will not work with fields). If this were my project, I would require that the structure / class be publicly available. If it is internal to the assembly or closed to the class, I could first ignore it and reorganize their read-only properties.

+1
May 19 '11 at 18:36
source share



All Articles