En primer lugar, las respuestas de Jon, Michael y Jared son esencialmente correctas, pero tengo algunas cosas más que me gustaría añadirles.
¿Qué significa un método "impuro"?
Es más fácil caracterizar los métodos puros. Un método "puro" tiene las siguientes características:
- Su salida está completamente determinada por su entrada; su salida no depende de externalidades como la hora del día o los bits en su disco duro. Su salida no depende de su historia; llamar al método con un argumento dado dos veces debería dar el mismo resultado.
- Un método puro no produce mutaciones observables en el mundo que lo rodea. Un método puro puede elegir mutar el estado privado por eficiencia, pero un método puro no cambia, digamos, un campo de su argumento.
Por ejemplo, Math.Cos
es un método puro. Su salida depende solo de su entrada, y la entrada no cambia por la llamada.
Un método impuro es un método que no es puro.
¿Cuáles son algunos de los peligros de pasar estructuras de solo lectura a métodos impuros?
Hay dos que vienen a la mente. El primero es el señalado por Jon, Michael y Jared, y este es el que Resharper te está advirtiendo. Cuando llamamos a un método en una estructura, siempre pasamos una referencia a la variable que es el receptor, en caso de que el método desee mutar la variable.
Entonces, ¿qué ocurre si llama a tal método en un valor, en lugar de una variable? En ese caso, hacemos una variable temporal, copiamos el valor en ella y pasamos una referencia a la variable.
Una variable de solo lectura se considera un valor, porque no se puede mutar fuera del constructor. Así que estamos copiando la variable a otra variable, y el método impuro posiblemente está mutando la copia, cuando pretendes mutar la variable.
Ese es el peligro de pasar una estructura readonly como un receptor . También existe el peligro de pasar una estructura que contenga un campo de solo lectura. Una estructura que contiene un campo de solo lectura es una práctica común, pero básicamente está escribiendo una verificación de que el sistema de tipo no tiene los fondos para cobrar; el propietario del almacenamiento determina la "capacidad de solo lectura" de una variable en particular. Una instancia de un tipo de referencia "posee" su propio almacenamiento, pero una instancia de un tipo de valor no lo hace.
struct S
{
private readonly int x;
public S(int x) { this.x = x; }
public void Badness(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
// This should be the same, right?
Console.WriteLine(this.x);
}
}
Se cree que this.x
no va a cambiar porque x es un campo de sólo lectura y Badness
no es un constructor. Pero ...
S s = new S(1);
s.Badness(ref s);
... demuestra claramente la falsedad de eso. this
y s
se refieren a la misma variable, y esa variable no es de solo lectura.
http://www.minddriven.de/index.php/technology/dot-net/code-contracts/code-contracts-method-purity – siride