Si vous devez utiliser des structs, il est préférable de les rendre immuables.
Rendre tous les champs en lecture seule est un excellent moyen de (1) documenter que la structure est immuable, et (2) d'empêcher les mutations accidentelles.
Cependant, il y a un problème, et par une étrange coïncidence, j'avais prévu d'en parler dans mon blog la semaine prochaine. C'est que : readonly sur un champ struct est un mensonge . On s'attend à ce qu'un champ en lecture seule ne puisse pas changer, mais bien sûr, c'est possible. "readonly" sur un champ struct est la déclaration qui fait des chèques sans argent sur son compte. Un struct ne possède pas son stockage, et c'est ce stockage qui peut muter.
Par exemple, prenons votre 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);
}
}
Y a-t-il quelque chose qui puisse se produire à "quelque chose se passe ici" et qui fasse que les assertions de débogage soient violées ? Bien sûr.
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);
Et maintenant, que se passe-t-il ? L'assertion est violée ! "this" et "p" font référence au même emplacement de stockage. L'emplacement de stockage est muté, et donc le contenu de "this" est muté car il s'agit de la même chose. La structure n'est pas en mesure de faire respecter le caractère de lecture seule de x et y car la structure ne possède pas le stockage ; le stockage est une variable locale qui est libre de muter autant qu'elle le souhaite.
Vous ne pouvez pas compter sur sur l'invariant qu'un champ en lecture seule dans une structure n'est jamais observé pour changer ; la seule chose sur laquelle vous pouvez compter est que vous ne pouvez pas écrire de code qui le change directement. Mais avec un petit travail sournois comme celui-ci, vous pouvez le modifier indirectement autant que vous voulez.
Voir également l'excellent article du blog de Joe Duffy sur cette question :
http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/