¿Los métodos de C # que * pueden * ser estáticos deberían ser estáticos? [cerrado]

103

¿Deberían ser estáticos los métodos de C # que pueden ser estáticos?

Estuvimos discutiendo esto hoy y estoy un poco indeciso. Imagina que tienes un método largo del que refactorizas algunas líneas. El nuevo método probablemente toma algunas variables locales del método principal y devuelve un valor. Esto significa que podría ser estático.

La pregunta es: ¿ debería ser estático? No es estático por diseño o elección, simplemente por su naturaleza, ya que no hace referencia a ningún valor de instancia.

Bernhard Hofmann
fuente
1
Duplicado bastante exacto de stackoverflow.com/questions/169378/…
JasonTrue
41
"bastante exacto" es un oxímoron
Matt Briggs
1
Resharper , la herramienta de herramientas de Visual Studio, dice que sí. :-)
Rebecca
@Junto Quizás en tu versión, pero la mía dice que se puede hacer estática ...
Robbie Dee

Respuestas:

59

Depende. Realmente hay 2 tipos de métodos estáticos:

  1. Métodos que son estáticos porque PUEDEN ser
  2. Métodos que son estáticos porque TIENEN que ser

En una base de código de tamaño pequeño a mediano, realmente puede tratar los dos métodos de manera intercambiable.

Si tiene un método que está en la primera categoría (puede ser estático) y necesita cambiarlo para acceder al estado de la clase, es relativamente sencillo averiguar si es posible convertir el método estático en un método de instancia.

Sin embargo, en una base de código grande, la gran cantidad de sitios de llamadas puede hacer que la búsqueda para ver si es posible convertir un método estático en uno no estático sea demasiado costosa. Muchas veces la gente verá la cantidad de llamadas y dirá "ok ... mejor no cambiar este método, sino crear uno nuevo que haga lo que necesito".

Eso puede resultar en:

  1. Mucha duplicación de código
  2. Una explosión en el número de argumentos de método

Ambas cosas son malas.

Entonces, mi consejo sería que si tiene una base de código de más de 200K LOC, solo haría que los métodos sean estáticos si son métodos que deben ser estáticos.

La refactorización de no estático a estático es relativamente fácil (solo agregue una palabra clave), por lo que si desea convertir un can-be-static en uno estático real más adelante (cuando necesite su funcionalidad fuera de una instancia), entonces puede hacerlo. Sin embargo, la refactorización inversa, convertir un método can-be-static en un método de instancia, es MUCHO más caro.

Con bases de código grandes, es mejor equivocarse por el lado de la facilidad de extensión, en lugar del lado de la pureza idealológica.

Por lo tanto, para proyectos grandes, no hagas las cosas estáticas a menos que lo necesites. Para proyectos pequeños, haga lo que más le guste.

Scott Wisniewski
fuente
43

Yo no lo convierten en un público miembro estático de la clase . La razón es que hacerlo público estático es decir algo sobre el tipo de clase: no solo "este tipo sabe cómo realizar este comportamiento", sino también "es responsabilidad de este tipo realizar este comportamiento". Y lo más probable es que el comportamiento ya no tenga una relación real con el tipo más grande.

Sin embargo, eso no significa que no lo haría estático en absoluto. Pregúntese esto: ¿podría el nuevo método lógicamente pertenecer a otra parte? Si puede responder "sí" a eso, probablemente quiera hacerlo estático (y moverlo también). Incluso si eso no es cierto, aún podría hacerlo estático. Simplemente no lo marques public.

Por conveniencia, al menos podría marcarlo internal. Por lo general, esto evita la necesidad de mover el método si no tiene acceso fácil a un tipo más apropiado, pero aún lo deja accesible donde sea necesario de una manera que no se mostrará como parte de la interfaz pública para los usuarios de su clase. .

Joel Coehoorn
fuente
6
Convenido. Generalmente hago que el método sea "privado estático" en un caso como este.
harpo
6
Yo tampoco asumiría estática privada. Lo principal es preguntarse: ¿este método encaja lógicamente como parte de este tipo, o solo está aquí por una cuestión de conveniencia? Si es lo último, ¿podría encajar mejor en otro lugar?
Joel Coehoorn
1
Como: "¿podría el nuevo método pertenecer lógicamente a otra parte" - la pista es que no depende del estado local, tal vez el tipo de retorno es donde pertenece?
AndyM
20

No necesariamente.

Mover los métodos públicos de estáticos a no estáticos es un cambio radical y requeriría cambios para todas las personas que llaman o consumidores. Si un método parece un método de instancia, pero resulta que no usa ningún miembro de instancia, sugeriría convertirlo en un método de instancia como una medida de prueba de futuro.

Miguel
fuente
Creo que se está refiriendo principalmente a métodos privados
George Mauer
@Ray - Correcto, esto solo se aplica a miembros no privados. Actualicé mi respuesta para reflejar esto.
Michael
Mis pensamientos exactamente - sólo porque usted podría hacer algo estático no significa que tenga que o debería .....
marc_s
Entonces, ¿qué harías con los métodos privados que podrían volverse estáticos?
Ray
@Ray: probablemente dejarlo como está hasta que tenga una razón suficiente para pasar a la estática.
Michael
13

Si. La razón por la que "puede ser estático" es que no opera en el estado del objeto sobre el que se llama. Por lo tanto, no es un método de instancia, sino un método de clase. Si puede hacer lo que debe hacer sin tener que acceder a los datos de la instancia, entonces debería ser estático.

JP Alioto
fuente
11

Sí, debería. Hay varias métricas de acoplamiento que miden cómo su clase depende de otras cosas, como otras clases, métodos, etc. Hacer que los métodos sean estáticos es una forma de mantener bajo el grado de acoplamiento, ya que puede estar seguro de que un método estático no hace referencia a ninguno. miembros.

Jabe
fuente
7
No necesariamente. Un método estático no accederá a la información de la instancia, no a los miembros, como dijiste, pero puede interactuar con otras clases así como con otro método común. Ser estático no significa necesariamente que el acoplamiento se reduzca. Sin embargo, entendí tu punto.
Victor Rodrigues
En lugar de eso, la estática realmente aumenta el acoplamiento, porque está limitado exactamente a ese método estático, no hay forma de desviarlo, por ejemplo, y por lo tanto no hay forma de cambiar el comportamiento.
HimBromBeere
8

Creo que lo haría un poco más legible si lo marcara como estático ... Entonces alguien que venga sabría que no hace referencia a ninguna variable de instancia sin tener que leer la función completa ...

Jason Punyon
fuente
6

Personalmente, soy un gran fanático de la apatridia. ¿Tu método necesita acceso al estado de la clase? Si la respuesta es no (y probablemente sea no, de lo contrario no consideraría convertirlo en un método estático), entonces sí, adelante.

No tener acceso al estado es menos dolor de cabeza. Así como es una buena idea ocultar los miembros privados que no son necesarios para otras clases, es una buena idea ocultar el estado a los miembros que no lo necesitan. El acceso reducido puede significar menos errores. Además, facilita el enhebrado, ya que es mucho más fácil mantener los miembros estáticos seguros para los subprocesos. También hay una consideración de rendimiento, ya que el tiempo de ejecución no necesita pasar una referencia a esto como un parámetro para los métodos estáticos.

Por supuesto, la desventaja es que si alguna vez descubre que su método previamente estático tendrá que acceder al estado por alguna razón, entonces debe cambiarlo. Ahora entiendo que esto puede ser un problema para las API públicas, por lo que si se trata de un método público en una clase pública, tal vez debería pensar un poco en las implicaciones de esto. Aún así, nunca me he enfrentado a una situación en el mundo real en la que esto realmente haya causado un problema, pero tal vez tenga suerte.

Así que sí, adelante, por supuesto.

Tamas Czinege
fuente
1
Un método estático todavía puede tener acceso al estado. Simplemente obtiene el estado del objeto que se le ha pasado. Por el contrario, los campos de instancia no contienen necesariamente un estado mutable.
Jørgen Fogh
6

Los métodos estáticos son más rápidos que los no estáticos, así que sí, deberían ser estáticos si pueden y no hay ninguna razón especial para dejarlos no estáticos .

Agnieszka
fuente
3
Eso es técnicamente cierto, pero no en un sentido material real. La diferencia entre estático / no será muy, muy raramente un factor en el rendimiento.
Foredecker
22
-1: Optimización prematura de libros de texto. Ciertamente, la velocidad no debería ser el primer criterio a la hora de decidir entre estática y no estática para el caso general.
No estoy seguro
2
De acuerdo con No estoy seguro, esta debería ser su última razón para considerar estático o no.
Samuel
5
Mi punto es que la velocidad es una de las razones más pobres que puede tener para decidir si una función es estática o no estática en el 99% de los casos. Hay consideraciones mucho más importantes cuando se trata del diseño de OO que otras publicaciones elaboran.
No estoy seguro
2
@agnieszka: La razón especial por la que generalmente se usan métodos de instancia en lugar de métodos estáticos es el estado. Si dejas tus métodos estáticos, en una aplicación compleja introducirás bichos que te harán arrancarte los pelos. Piense en modificar el estado global, las condiciones de la carrera, la seguridad de los hilos, etc.
Sandor Davidhazi
5

Me sorprende que, de hecho, tan pocos mencionen la encapsulación aquí. Un método de instancia tendrá acceso automáticamente a todos los campos, propiedades y métodos privados (de instancia). Además de todos los protegidos heredados de las clases base.

Cuando escribes código debes hacerlo de modo que expongas lo menos posible y también para que tengas acceso a lo menos posible.

Entonces, sí, podría ser importante hacer que su código sea rápido, lo que sucedería si está haciendo que sus métodos sean estáticos, pero generalmente es más importante hacer que su código sea lo más incapaz posible de crear errores también. Una forma de lograrlo es que su código tenga acceso a la menor cantidad posible de "cosas privadas".

Esto puede parecer irrelevante a primera vista, ya que el OP está hablando obviamente de refactorización que no puede salir mal en este escenario y crear nuevos errores, sin embargo, este código refactorizado debe mantenerse en el futuro y modificarse, lo que hace que su código tenga un mayor "ataque". Surface "con respecto a nuevos errores si tiene acceso a miembros de instancias privadas. Entonces, en general, creo que la conclusión aquí es que "sí, la mayoría de sus métodos deben ser estáticos" a menos que haya otras razones para no tenerlos estáticos. Y esto simplemente porque es "un mejor uso de la encapsulación y el ocultamiento de datos y crea un código 'más seguro'" ...

Thomas Hansen
fuente
4

Hacer algo estático solo porque puedes no es una buena idea. Los métodos estáticos deben ser estáticos debido a su diseño, no por casualidad.

Como dijo Michael, cambiar esto más tarde romperá el código que lo está usando.

Dicho esto, parece que está creando una función de utilidad privada para la clase que, de hecho, es estática por diseño.

17 de 26
fuente
4

Si pudo refactorizar algunas líneas y el método resultante podría ser estático, probablemente sea una indicación de que las líneas que sacó de ese método no pertenecen en absoluto a la clase contenedora, y debería considerar moverlas a su propia clase.

Chris Shaffer
fuente
2

Personalmente, no tendría más remedio que hacerlo estático. Resharper emite una advertencia en este caso y nuestro PM tiene una regla "No hay advertencias del Resharper".

Bromista
fuente
1
Puede cambiar la configuración de ReSharper: P
Bernhard Hofmann
1
Si fuera tan fácil, no tendríamos ningún desgaste del Resharper ... nunca :)
Bromista
1

Depende, pero generalmente no hago que esos métodos sean estáticos. El código siempre cambia y quizás algún día quiera hacer que esa función sea virtual y anularla en una subclase. O quizás algún día tendrá que hacer referencia a variables de instancia. Será más difícil realizar esos cambios si es necesario cambiar todos los sitios de llamadas.

Brian Ensink
fuente
Sí, pero si algún día necesitas hacer esto, siempre puedes hacer que no sea estático. ¿O me estoy perdiendo algo?
Ray
1
@Ray: cubro esto en mi respuesta. De estático a no estático es un cambio radical, por lo que todos los consumidores deben modificarse. No es gran cosa para un programa pequeño, pero si se trata de una biblioteca para consumo de otros, hay que tenerlo en cuenta.
Michael
Todos los sitios de llamada deben cambiarse de una llamada a un método estático a una llamada a una función miembro.
Brian Ensink
Lo siento, lo agregaste después de mi comentario. En mi mente, estaba pensando en métodos privados, pero ese es un punto válido para los métodos públicos.
Ray
... o algún día puedes tirarlo. estos argumentos no son lo suficientemente buenos como para hacer que un método no sea estático.
agnieszka
1

Sugiero que la mejor manera de pensarlo es la siguiente: si necesita un método de clase que deba llamarse cuando no se crean instancias de la clase, o mantiene algún tipo de estado global, entonces estático es una buena idea. Pero, en general, sugiero que prefiera que los miembros no sean estáticos.

Foredecker
fuente
1

Deberías pensar en tus métodos y clases:

  • ¿Cómo los vas a utilizar?
  • ¿Necesita mucho acceso a ellos desde diferentes niveles de su código?
  • ¿Es este un método / clase que puedo usar en casi todos los proyectos imaginables?

Si los dos últimos son 'sí', entonces su método / clase probablemente debería ser estático.

El ejemplo más utilizado es probablemente el Math clase. Todos los principales lenguajes OO lo tienen y todos los métodos son estáticos. Porque necesitas poder usarlos en cualquier lugar, en cualquier momento, sin crear una instancia.

Otro buen ejemplo es el Reverse()método en C #.
Este es un método estático en elArray clase. Invierte el orden de su matriz.

Código:

public static void Reverse(Array array)

Ni siquiera devuelve nada, su matriz se invierte, porque todas las matrices son instancias de la clase Array.

KdgDev
fuente
Las matemáticas son un mal ejemplo. Supongo que es mejor: newnumber = number.round (2) que newnumber = Math.round (número)
graffic
3
La clase de matemáticas es el ejemplo perfecto del uso de clases estáticas. De eso se trata este tema, no de cómo prefiere redondear números ...
KdgDev
1

Siempre que haga que el nuevo método sea privado y estático, no será un cambio importante. De hecho, FxCop incluye esta guía como una de sus reglas ( http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx ), con la siguiente información:

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

Dicho esto, el primer comentario de David Kean resume de manera más sucinta las preocupaciones diciendo que en realidad se trata más de ser correcto que de mejorar el rendimiento:

Aunque esta regla se clasifica como un problema de rendimiento, la mejora del rendimiento de convertir un método en estático es solo de alrededor del 1%. Más bien, es más un problema de corrección que podría indicar un error o un error en el miembro por no usar otros miembros de la instancia. Marcar un método como estático ( Compartido en Visual Basic) deja en claro su intención de no tocar el estado de la instancia.

Scott Dorman
fuente
1

Definitivamente convertiría todo lo que pueda en estático por una razón diferente:

Las funciones estáticas, cuando están JIT, se llaman sin un parámetro "this". Eso significa, por ejemplo, que una función no estática de 3 parámetros (método de miembro) se inserta con 4 parámetros en la pila.

La misma función compilada como función estática se llamaría con 3 parámetros. Esto puede liberar registros para el JIT y ahorrar espacio en la pila ...

Daño chico
fuente
1

Estoy en el campo de "solo hacer estáticos los métodos privados". Hacer un método público puede introducir un acoplamiento que no desea y puede disminuir la capacidad de prueba: no puede bloquear un método estático público.

Si desea realizar una prueba unitaria de un método que usa un método estático público, también terminará probando el método estático, que podría no ser lo que desea.

Lennaert
fuente
1

Los métodos inherentemente estáticos que por alguna razón se hacen no estáticos son simplemente molestos. Esto es:

Llamo a mi banco y pregunto por mi saldo.
Piden mi número de cuenta.
Lo suficientemente justo. Método de instancia.

Llamo a mi banco y les pido su dirección postal.
Piden mi número de cuenta.
WTF? Fallar: debería haber sido un método estático.

IJ Kennedy
fuente
1
¿Qué pasa si diferentes sucursales atienden a diferentes clientes? Enviar correspondencia a la oficina principal del banco puede llevarla a la sucursal adecuada, eventualmente, pero eso no significa que un cliente no estaría mejor atendido si usa la dirección de la sucursal en particular que lo atiende.
supercat
0

Lo miro generalmente desde una perspectiva funcional de funciones puras. ¿Necesita ser un método de instancia? De lo contrario, puede beneficiarse de obligar al usuario a pasar las variables y no alterar el estado de la instancia actual. (Bueno, aún podría alterar el estado, pero el punto es, por diseño, no hacerlo). Generalmente diseño métodos de instancia como miembros públicos y hago todo lo posible para que los miembros privados sean estáticos. Si es necesario (puede extraerlos más fácilmente en otras clases más adelante.


fuente
-1

En esos casos, tiendo a mover el método a una biblioteca estática o utils, así que no estoy mezclando el concepto de "objeto" con el concepto de "clase".

Jhonny D. Cano -Leftware-
fuente