2008-10-04 16 views
317

Resharper le gusta señalar funciones múltiples por página asp.net que podrían estar estáticas. ¿Me ayuda si los hago estáticos? ¿Debo hacerlos estáticos y moverlos a una clase de utilidad?El método se puede hacer estático, pero ¿debería?

+17

¿No es Resharper realmente gritando "baja cohesión, baja cohesión"? es hora de ver si el método realmente pertenece a esa clase. –

+1

posible duplicado de [Ventajas de usar métodos estáticos privados] (http://stackoverflow.com/questions/135020/advantages-to-using-private-static-methods) – drzaus

Respuesta

215

Los métodos estáticos en comparación con los métodos de instancia
10.2.5 Static and instance members de la especificación del lenguaje C# explica la diferencia. En general, los métodos estáticos pueden proporcionar una mejora de rendimiento muy pequeña en comparación con los métodos de instancia, pero solo en situaciones algo extremas (consulte this answer para obtener más información al respecto).

Regla CA1822 en FxCop o análisis de código establece:

"Después [miembros como estática marca], el compilador emitirá sitios de llamadas no virtuales a estos miembros que eviten un cheque en tiempo de ejecución para cada llamada que garantiza que el puntero del objeto actual es no nulo. Esto puede dar como resultado una ganancia de rendimiento medible para el código sensible al rendimiento . En algunos casos, el error al acceder a la instancia del objeto actual representa un problema de corrección ".

utilidad de la clase
Usted 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 método ToRadians(double degrees) se refiere a 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 complicado para los propósitos de la demostración) .

+2

> el compilador emitirá sitios de llamadas no virtuales a estos miembros En realidad eso es "el compilador puede emitir ...". Recuerdo algo sobre el compilador de C# que usa callvirt en lugar de llamar para solucionar algunos posibles errores. –

+22

Lo corté y lo pegué directamente desde FxCop 1.36. Si FxCop está equivocado, es suficiente. –

+5

@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 las cosas un poco (fue hace 9 años, así que no recuerdo la base de mi afirmación original). –

2

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

+8

¿De qué manera la creación de un método estático ayuda a evitar la contaminación del espacio de nombres? – lockstock

+1

Por experiencia, al agrupar métodos en clases con métodos estáticos, está evitando la experiencia de tener que prefijar toda la "bolsa de sorpresas" de funciones sueltas que pueden entrar en conflicto con otra biblioteca o funciones incorporadas. Con métodos estáticos, están efectivamente espaciados bajo el nombre de clase, ej. 'Class.a_core_function (..)' versus 'a_core_function (..)' – lintuxvi

5

Debe hacer lo que es más legible e intuitivo en un escenario determinado.

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 extra (this) está siendo empujado a la pila por ejemplo métodos.

2

Si las funciones se comparten en muchas páginas, también puede ponerlas en una clase de página base, y luego tener todas las páginas asp.net que usen esa funcionalidad heredada (y las funciones también podrían ser estáticas).

19

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 por mantener el uso de una gran cantidad de métodos estáticos.

Desafortunadamente, eran métodos estáticos que asumían un estado de aplicación particular. (¿Por qué no, solo tendremos un usuario por aplicación! ¿Por qué no hacer que la clase de Usuario haga un seguimiento de eso en variables estáticas?) Eran formas glorificadas 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 tienen en cuenta la lógica de dominio que en realidad no depende del estado de una instancia del objeto. Pueden hacer que tu código sea mucho más legible.

Solo asegúrese de que los está poniendo en el lugar correcto. ¿Los métodos estáticos manipulan 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.

+0

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

46

Marcar un método como static dentro de una clase, hace que sea obvio que no utiliza ningún miembro de instancia que pueda ser útil para conocer al pasar por 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, conceptualmente.

2

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 de terceros o complementos. Imagine si primero tenía que crear un objeto de consola "con" antes de llamar a con.Writeline();

233

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

A veces hay métodos que lógicamente actúan en una instancia pero que no usan el estado de la instancia todavía. Por ejemplo, si estuviese construyendo 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 debe ser un método de instancia. Esto también es importante si desea que el método sea virtual: su implementación particular puede no necesitar estado, pero las clases derivadas sí pueden. (Por ejemplo, preguntar a una colección si es de solo lectura o no; aún no ha implementado una forma de solo lectura de esa colección, pero es claramente una propiedad de la colección en sí, no del tipo).

+0

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 haga prácticamente nada. Los métodos de anulación suelen hacer algo, pero no siempre. A veces es útil tener una clase para algo así como un iEnumerable vacío, cuyos métodos esencialmente ignoran la instancia, pero donde la instancia es requerida para seleccionar el método correcto para usar. – supercat

6

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

6

Para lógica compleja dentro de una clase, he encontrado que los métodos estáticos privados son útiles para crear una 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 colaterales. Todas las salidas deben ser a través del valor de retorno o los parámetros de salida/ref. Descomponer 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 una proliferación de métodos de utilidad. Como es habitual, la nomenclatura lógica, la documentación y la aplicación coherente de las convenciones de codificación de equipo pueden aliviar esto.

5

ReSharper no comprueba la lógica. Solo verifica si el método usa miembros de la instancia. Si el método es privado y solo lo llaman (tal vez solo uno) de los métodos de instancia, este es un signo para permitir que sea un método de instancia.

6

Esto es interesante lectura:

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

ReSharper no es en realidad lo que sugiere que haga su método estático. usted debe preguntarse por qué ese método es en esa clase en lugar de, digamos, una de las clases que se muestra en su firma ...

pero aquí es lo que dice documentaion ReSharper: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

+0

Creo que este punto está subestimado. Lo que realmente te dice la herramienta 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 clase única que se parece mucho a [Feature Envy] (http://wiki.c2.com/?FeatureEnvySmell). – Greg

0

Justo mi peniques: Adición de todos los métodos estáticos compartidas a una clase de utilidad le permite añadir

using static className; 

a sus declaraciones utilizando, lo que hace el código más rápido de escribir y más fácil de leer. Por ejemplo, tengo un gran número de lo que se llamaría "variables globales" en algún código que heredé. En lugar de hacer 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 puedo simplemente hacer referencia a las propiedades por su nombre porque ya tengo el espacio de nombres estático al que se hace referencia.

No tengo idea si esto es una buena práctica o no. Tengo tanto para 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

Cuestiones relacionadas