Estoy usando Visual Studio 2010 + Resharper y muestra una advertencia en el siguiente código:
if (rect.Contains(point))
{
...
}
rect
es un readonly Rectangle
campo, y Resharper me muestra esta advertencia:
"Impure Method se llama para campos de solo lectura de tipo de valor".
¿Qué son los métodos impuros y por qué se me muestra esta advertencia?
Respuestas:
En primer lugar, las respuestas de Jon, Michael y Jared son esencialmente correctas, pero tengo algunas cosas más que me gustaría agregarles.
Es más fácil caracterizar métodos puros. Un método "puro" tiene las siguientes características:
Por ejemplo,
Math.Cos
es un método puro. Su salida depende solo de su entrada y la entrada no se modifica con la llamada.Un método impuro es un método que no es puro.
Hay dos que me vienen a la mente. El primero es el señalado por Jon, Michael y Jared, y este es el que te advierte Resharper. Cuando llama 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é pasa si llama a un método de este tipo en un valor, en lugar de una variable? En ese caso, creamos 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. Entonces, estamos copiando la variable a otra variable, y el método impuro posiblemente está mutando la copia, cuando usted tiene la intención de que mute la variable.
Ese es el peligro de pasar una estructura de solo lectura como receptor . También existe el peligro de pasar una estructura que contiene un campo de solo lectura. Una estructura que contiene un campo de solo lectura es una práctica común, pero esencialmente se trata de emitir un cheque que el sistema de tipos no tiene los fondos para cobrar; la "condición de sólo lectura" de una variable en particular la determina el propietario del almacenamiento. Una instancia de un tipo de referencia "posee" su propio almacenamiento, ¡pero una instancia de un tipo de valor no!
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); } }
Uno piensa que eso
this.x
no va a cambiar porque x es un campo de solo lectura yBadness
no es un constructor. Pero...S s = new S(1); s.Badness(ref s);
... demuestra claramente la falsedad de eso.
this
y hacens
referencia a la misma variable, ¡y esa variable no es de solo lectura!fuente
struct Id {
private readonly int _id;
public Id(int id) { _id = id; }
public int ToInt() => _id;
}
¿Por qué ToInt es impuro?return
. Basado en eso, supongo que el único criterio es si el método tiene el[Pure]
atributo o no .rect
. ¿Estamos diciendo querect
se pasa una copia deContains
método?Un método impuro es aquel que no garantiza que deje el valor como estaba.
En .NET 4 puede decorar métodos y tipos con
[Pure]
para declararlos puros, y R # se dará cuenta de esto. Desafortunadamente, no puede aplicarlo a los miembros de otra persona, y no puede convencer a R # de que un tipo / miembro es puro en un proyecto .NET 3.5 hasta donde yo sé. (Esto me muerde en Noda Time todo el tiempo).La idea es que si está llamando a un método que muta una variable, pero lo llama en un campo de solo lectura, probablemente no esté haciendo lo que desea, por lo que R # le advertirá sobre esto. Por ejemplo:
public struct Nasty { public int value; public void SetValue() { value = 10; } } class Test { static readonly Nasty first; static Nasty second; static void Main() { first.SetValue(); second.SetValue(); Console.WriteLine(first.value); // 0 Console.WriteLine(second.value); // 10 } }
Esta sería una advertencia realmente útil si todos los métodos que en realidad fueran puros fueran declarados de esa manera. Lamentablemente no lo son, por lo que hay muchos falsos positivos :(
fuente
JetBrains.Annotations.PureAttribute
lugar deSystem.Diagnostics.Contracts.PureAttribute
, tienen el mismo significado para el análisis de código de ReSharper y deberían funcionar igualmente en .NET 3.5, .NET 4 o Silverlight. También puede anotar externamente ensamblajes que no posee usando archivos XML (eche un vistazo al directorio ExternalAnnotations en la ruta bin de ReSharper), ¡realmente puede ser bastante útil!System.Diagnostics.Contracts.PureAttribute
no suprimió esta advertencia en R # 8.2, mientras que loJetBrains.Annotations.PureAttribute
hizo. Los dos atributos también tienen descripciones diferentes: elPure
atributo contratos implica "el resultado depende sólo de los parámetros", mientras que JetBrainsPure
implica "no causa cambios de estado visibles" sin excluir el estado del objeto que se utiliza para calcular el resultado. (Pero aún así los contratos quePure
no tienen el mismo efecto en esta advertencia probablemente sea un error).La respuesta corta es que se trata de un falso positivo y puede ignorar la advertencia con seguridad.
La respuesta más larga es que acceder a un tipo de valor de solo lectura crea una copia del mismo, por lo que cualquier cambio en el valor realizado por un método solo afectaría la copia. ReSharper no se da cuenta de que
Contains
es un método puro (lo que significa que no tiene efectos secundarios). Eric Lippert habla de ello aquí: Mutación de estructuras de solo lecturafuente
private readonly SpinLock _spinLock = new SpinLock();
- un bloqueo de este tipo sería completamente inútil (ya que sólo lectura causas modificadoras de la marcha de la copia que se crea cada vez que se llama método Introduzca en él)Parece que Reshaprer cree que el método
Contains
puede mutar elrect
valor. Debido a querect
es un,readonly struct
el compilador de C # hace copias defensivas del valor para evitar que el método mute unreadonly
campo. Básicamente, el código final se ve asíRectangle temp = rect; if (temp.Contains(point)) { ... }
Resharper le advierte aquí que
Contains
puede mutarrect
de una manera que se perdería inmediatamente porque sucedió de forma temporal.fuente
Un método impuro es un método que puede tener efectos secundarios. En este caso, Resharper parece pensar que podría cambiar
rect
. Probablemente no sea así, pero la cadena de pruebas está rota.fuente