El método puede hacerse estático, pero ¿debería?


366

A Resharper le gusta señalar múltiples funciones por página asp.net que podrían hacerse estáticas. ¿Me ayuda si los hago estáticos? ¿Debo hacerlos estáticos y moverlos a una clase de utilidad?


20
¿Acaso Resharper no está gritando "baja cohesión, baja cohesión"? Es hora de ver si el método realmente pertenece a esa clase.
PK

Respuestas:


245

Métodos estáticos versus métodos de instancia
10.2.5 Los miembros estáticos y de instancia de la especificación del lenguaje C # explican la diferencia. En general, los métodos estáticos pueden proporcionar una mejora de rendimiento muy pequeña sobre los métodos de instancia, pero solo en situaciones algo extremas (consulte esta respuesta para obtener más detalles al respecto).

La regla CA1822 en FxCop o Code Analysis establece:

"Después de [marcar miembros como estáticos], el compilador emitirá sitios de llamadas no virtuales a estos miembros, lo que evitará una verificación en tiempo de ejecución para cada llamada que garantice que el puntero del objeto actual no sea nulo. Esto puede resultar en una ganancia de rendimiento medible para código sensible al rendimiento. En algunos casos, el hecho de no acceder a la instancia del objeto actual representa un problema de corrección ".

Clase de utilidad
No debe moverlos a una clase de utilidad a menos que tenga sentido en su diseño. Si el método estático se relaciona con un tipo particular, como un ToRadians(double degrees)método se relaciona con una clase que representa ángulos, tiene sentido que ese método exista como un miembro estático de ese tipo (nota, este es un ejemplo enrevesado para fines de demostración).


2
> el compilador emitirá sitios de llamadas no virtuales a estos miembros En realidad es "el compilador puede emitir ...". Recuerdo algo sobre el compilador de C # usando callvirt en lugar de llamar para evitar algún error potencial.
Jonathan Allen el

24
Lo corto y lo pego directamente desde FxCop 1.36. Si FxCop está mal, es justo.
Jeff Yates

55
@Maxim No estoy seguro de apreciar la declaración de "mierda"; manera bastante grosera de acercarse a extraños. Sin embargo, el punto subyacente es válido; He actualizado un poco las cosas (fue hace 9 años, así que no recuerdo los fundamentos de mi reclamo original).
Jeff Yates

10
@Maxim Su punto no es válido. Les aseguro que no tenía una buena calificación hace 9 años. Agradezco los comentarios que señalan errores (o ediciones que los corrigen), pero no sea grosero ni exija expectativas irracionales a los demás. No llames a algo "mierda"; implica una intención de engañar en lugar de ser honesto con el error o la ignorancia. Es grosero. Ofrezco voluntariamente mi tiempo para ayudar aquí y realmente se siente inútil cuando se trata con falta de respeto. No me digas por qué ofenderte, esa es mi elección, no la tuya. Aprenda cómo expresar su punto con respeto e integridad. Gracias.
Jeff Yates

2
@Maxim Si bien los delegados no se almacenan junto a cada instancia, cada instancia de una clase sin estado ocupa algo de memoria en el montón, que es una sobrecarga inútil. Por lo general, la creación de instancias de servicios no es la ruta de acceso rápida en una aplicación, pero si su aplicación termina construyendo muchos de estos objetos, aumentará la presión de GC que podría evitarse simplemente usando métodos estáticos. La afirmación original del OP, de que en situaciones extremas los métodos estáticos proporcionan un beneficio de rendimiento sobre las instancias sin estado, fue adecuadamente matizada y válida.
Asad Saeeduddin

259

El rendimiento, la contaminación del espacio de nombres, etc. son todos secundarios en mi opinión. Pregúntate qué es lógico. ¿Funciona lógicamente el método en una instancia del tipo o está relacionado con el tipo en sí? Si es lo último, conviértalo en un método estático. Solo muévalo a una clase de utilidad si está relacionado con un tipo que no está bajo su control.

A veces hay métodos que actúan lógicamente en una instancia pero no pasan a utilizar cualquiera de estado de la instancia todavía . Por ejemplo, si estuviera creando un sistema de archivos y tuviera el concepto de un directorio, pero aún no lo hubiera implementado, podría escribir una propiedad que devuelva el tipo de objeto del sistema de archivos, y siempre sería solo "archivo", pero está lógicamente relacionado con la instancia, por lo que debería ser un método de instancia. Esto también es importante si desea hacer que el método sea virtual; su implementación particular puede no necesitar estado, pero las clases derivadas pueden. (Por ejemplo, preguntarle a una colección si es de solo lectura o no, es posible que todavía no haya implementado una forma de solo lectura de esa colección, pero es claramente una propiedad de la colección en sí, no del tipo).


1
Creo que un buen linter debería tener una opción para restringir el mensaje a métodos no virtuales, ya que sería muy común que un método de clase base no hiciera prácticamente nada. Los métodos de anulación generalmente harían algo, pero no siempre. A veces es útil tener una clase para algo como un iEnumerable vacío, cuyos métodos esencialmente ignoran la instancia, pero donde se requiere que la instancia seleccione el método correcto para usar.
supercat

2
"A veces hay métodos que lógicamente actúan en una instancia, pero todavía no usan ninguno de los estados de la instancia. Por ejemplo" Disfruté el uso de "por ejemplo" en esta instancia.
PaulBinder

56

Marcar un método como staticdentro de una clase hace que sea obvio que no usa ningún miembro de instancia, lo que puede ser útil para saber al hojear el código.

No necesariamente tiene que moverlo a otra clase a menos que esté destinado a ser compartido por otra clase que esté tan estrechamente asociada, en cuanto al concepto.


22

Estoy seguro de que esto no está sucediendo en su caso, pero un "mal olor" que he visto en algún código que he tenido que sufrir al mantener usado muchos métodos estáticos.

Desafortunadamente, eran métodos estáticos que asumían un estado de aplicación particular. (¡por qué seguro, solo tendremos un usuario por aplicación! ¿Por qué no hacer que la clase Usuario haga un seguimiento de eso en las variables estáticas?) Fueron formas gloriosas de acceder a las variables globales. También tenían constructores estáticos (!), Que casi siempre son una mala idea. (Sé que hay un par de excepciones razonables).

Sin embargo, los métodos estáticos son bastante útiles cuando factorizan la lógica de dominio que en realidad no depende del estado de una instancia del objeto. Pueden hacer que su código sea mucho más legible.

Solo asegúrese de colocarlos en el lugar correcto. ¿Los métodos estáticos están manipulando intrusivamente el estado interno de otros objetos? ¿Se puede argumentar que su comportamiento pertenece a una de esas clases? Si no está separando las preocupaciones adecuadamente, es posible que tenga dolores de cabeza más adelante.


44
Su problema es con campos / propiedades estáticos, no con métodos estáticos.
Asad Saeeduddin

10

Esta es una lectura interesante:

http://thecuttingledge.com/?p=57

ReSharper no está sugiriendo que haga que su método sea estático. Debería preguntarse por qué ese método está en esa clase en lugar de, por ejemplo, una de las clases que aparece en su firma ...

pero esto es lo que dice documentary resharper: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
Creo que este punto está subestimado. Lo que la herramienta realmente te dice es que el método solo funciona en los miembros de otras clases. Si se trata de algún tipo de objeto de comando (o "caso de uso" o "interactor"), quién tiene la responsabilidad de manipular otros objetos, está bien. Sin embargo, si solo manipula una sola clase que se parece mucho a Feature Envy .
Greg

9

Solo para agregar a la respuesta de @Jason True , es importante darse cuenta de que solo poner "estático" en un método no garantiza que el método sea "puro". No tendrá estado con respecto a la clase en la que se declara, pero bien puede acceder a otros objetos 'estáticos' que tienen estado (configuración de la aplicación, etc.), esto no siempre puede ser algo malo, pero una de las razones por las que Personalmente, prefiero los métodos estáticos cuando puedo, es que si son puros, puede probarlos y razonar sobre ellos de forma aislada, sin tener que preocuparse por el estado circundante.


6

Debe hacer lo que sea más legible e intuitivo en un escenario dado.

El argumento de rendimiento no es bueno, excepto en las situaciones más extremas, ya que lo único que realmente está sucediendo es que un parámetro adicional ( this) se está introduciendo en la pila por ejemplo.


6

Para la lógica compleja dentro de una clase, he encontrado que los métodos estáticos privados son útiles para crear lógica aislada, en la que las entradas de instancia están claramente definidas en la firma del método y no pueden producirse efectos secundarios de instancia. Todas las salidas deben ser a través del valor de retorno o los parámetros out / ref. Desglosar la lógica compleja en bloques de código sin efectos secundarios puede mejorar la legibilidad del código y la confianza del equipo de desarrollo en él.

Por otro lado, puede conducir a una clase contaminada por la proliferación de métodos de utilidad. Como de costumbre, la denominación lógica, la documentación y la aplicación coherente de las convenciones de codificación del equipo pueden aliviar esto.


5

ReSharper no verifica la lógica. Solo verifica si el método usa miembros de instancia. Si el método es privado y solo es llamado por (quizás solo uno) métodos de instancia, esto es una señal para permitirle un método de instancia.


3

Si las funciones se comparten en muchas páginas, también podría colocarlas en una clase de página base y, a continuación, heredar todas las páginas asp.net que utilicen esa funcionalidad (y las funciones también podrían ser estáticas).


3

Hacer que un método sea estático significa que puede llamar al método desde fuera de la clase sin crear primero una instancia de esa clase. Esto es útil cuando se trabaja con objetos o complementos de proveedores externos. Imagine si primero tuviera que crear un objeto de consola "con" antes de llamar a con.Writeline ();


Java debería crear una instancia de fábrica para crear el objeto Console antes de llamar a con.Writeline ().
ScottMichaud

2

Ayuda a controlar la contaminación del espacio de nombres.


8
¿Cómo hacer que un método estático ayude a evitar la contaminación del espacio de nombres?
Lockstock

1
Por experiencia, al agrupar los métodos en clases con métodos estáticos, está evitando la experiencia de tener que prefijar todas las "bolsas" de funciones sueltas que pueden entrar en conflicto con otra biblioteca o funciones integradas. Con métodos estáticos, están efectivamente espacios de nombres bajo el Nombre de clase, ej. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi

0

Solo mi tuppence: agregar todos los métodos estáticos compartidos a una clase de utilidad le permite agregar

using static className; 

a sus declaraciones de uso, lo que hace que el código sea más rápido de escribir y más fácil de leer. Por ejemplo, tengo una gran cantidad de lo que se llamarían "variables globales" en algún código que heredé. En lugar de crear variables globales en una clase que era una clase de instancia, las configuré todas como propiedades estáticas de una clase global. Hace el trabajo, si es desordenado, y solo puedo hacer referencia a las propiedades por nombre porque ya tengo referenciado el espacio de nombres estático.

No tengo idea si esta es una buena práctica o no. Tengo mucho que aprender sobre C # 4/5 y tanto código heredado para refactorizar que solo estoy tratando de dejar que los consejos de Roselyn me guíen.

Joey


0

Espero que ya haya entendido la diferencia entre los métodos estáticos y de instancia. Además, puede haber una respuesta larga y una respuesta corta. Las respuestas largas ya son proporcionadas por otros.

Mi respuesta corta: Sí, puedes convertirlos a métodos estáticos si Resharper sugiere. No hay daño al hacerlo. Más bien, al hacer que el método sea estático, en realidad lo está protegiendo para que, innecesariamente, no deslice a ningún miembro de la instancia a ese método. De esa manera, puede lograr un principio de OOP " Minimizar la accesibilidad de clases y miembros ".

Cuando ReSharper sugiere que un método de instancia se puede convertir en un método estático, en realidad le dice: "¿Por qué ... este método está en esta clase ya que no está utilizando ninguno de sus estados?" Entonces, te da que pensar. Entonces, es usted quien puede darse cuenta de la necesidad de mover ese método a una clase de utilidad estática o no. De acuerdo con los principios de SOLID, una clase debe tener solo una responsabilidad central. Entonces, puedes hacer una mejor limpieza de tus clases de esa manera. A veces, necesita algunos métodos auxiliares incluso en su clase de instancia. Si ese es el caso, puede mantenerlos dentro de un #region helper.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.