Ventajas de usar métodos estáticos privados


209

Al crear una clase que tiene métodos privados internos, generalmente para reducir la duplicación de código, que no requieren el uso de ningún campo de instancia, ¿existen ventajas de rendimiento o memoria para declarar el método como estático?

Ejemplo:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample"))
{
    string first = GetInnerXml(element, ".//first");
    string second = GetInnerXml(element, ".//second");
    string third = GetInnerXml(element, ".//third");
}

...

private static string GetInnerXml(XmlElement element, string nodeName)
{
    return GetInnerXml(element, nodeName, null);
}

private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue)
{
    XmlNode node = element.SelectSingleNode(nodeName);
    return node == null ? defaultValue : node.InnerXml;
}

¿Hay alguna ventaja en declarar los métodos GetInnerXml () como estáticos? No hay respuestas de opinión por favor, tengo una opinión.


Respuestas:


221

Desde la página de reglas de FxCop sobre esto:

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 garantice 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.


37
También agregaría que una cláusula "estática" no daña y ya proporciona "documentación" con 1 palabra. Le dice que este método no está utilizando ningún miembro de la instancia, y obtiene esta documentación casi gratis
frandevel

20
Llegaría a decir: "Si un método no necesita acceso de estado (esto), hágalo estático" como regla general.
DanMan

3
En aras del equilibrio, vale la pena señalar que muchas personas generalmente están en contra de los métodos estáticos porque rompen el polimorfismo y significan que el objeto no se puede tropezar para la prueba. por ejemplo ver googletesting.blogspot.co.uk/2008/12/…
Andy

@ Andy - Buen punto. Una forma de trazar la línea sería observar si el método estático está accediendo a algo fuera de los parámetros que ingresa. Siempre y cuando sea autónomo de esta manera, debería ser fácil de probar y no es necesario tropezar cualquier cosa.
Neil

44
Muchos desarrolladores no están familiarizados con la "estática privada". Lo he usado en la base de código común de mi equipo y ha generado confusión. A cambio, proporciona un beneficio muy menor. Podríamos elegir educar a todos en el equipo, incluidos todos los futuros desarrolladores que mantengan el código, en cuanto a lo que significa. Pero el beneficio de cambiar un método privado a una estática privada es tan pequeño (es decir, eliminar la dependencia de los datos de la instancia) que no vale la pena el esfuerzo y la confusión. El método ya es de ámbito privado de cualquier manera. Es una peculiaridad del lenguaje que no es realmente necesario saber.
Curtis Yallop

93

Cuando escribo una clase, la mayoría de los métodos se dividen en dos categorías:

  • Métodos que usan / cambian el estado de la instancia actual.
  • Métodos auxiliares que no usan / cambian el estado del objeto actual, pero me ayudan a calcular los valores que necesito en otro lugar.

Los métodos estáticos son útiles, porque con solo mirar su firma, sabes que la llamada no usa ni modifica el estado de la instancia actual.

Toma este ejemplo:

Biblioteca de clase pública
{
    libro estático privado findBook (Lista de libros <Book>, título de cadena)
    {
        // el código va aquí
    }
}

Si alguna vez se estropea una instancia del estado de la biblioteca, y estoy tratando de averiguar por qué, puedo descartar que FindBook sea el culpable, solo por su firma.

Intento comunicarme todo lo que puedo con la firma de un método o función, y esta es una excelente manera de hacerlo.


1
Tipo de declaración const-method en C ++, ¿no?
anhoppe

Sí, esa es otra buena manera de usar el lenguaje para simplificar las cosas al limitar lo que podría salir mal.
Neil

Esto no es necesariamente cierto. Vamos a suponer que una Librarytiene un campo de instancia List<Book> _bookspara almacenarlo de libros (no cómo le gustaría diseñar una Libraryclase, probablemente, pero w / e), y pasa a esta lista findBook, y que las llamadas a métodos estáticos books.Clear()o books.Reverse()y así sucesivamente. Si le da acceso a un método estático a una referencia a algún estado mutable, entonces ese método estático puede arruinar su estado.
Sara

1
Cierto. Y en ese caso, la firma nos mostraría que este método tenía acceso (y la capacidad de mutar) una instancia de Library.
Neil

Para prácticamente cualquier construcción protectora que podamos usar, hay alguna forma de socavarla. Pero usarlos sigue siendo sabio y ayuda a empujarnos en la dirección correcta, hacia el "pozo del éxito".
Neil

81

Una llamada a un método estático genera una instrucción de llamada en el lenguaje intermedio de Microsoft (MSIL), mientras que una llamada a un método de instancia genera una instrucción callvirt, que también busca referencias de objetos nulos. Sin embargo, la mayoría de las veces la diferencia de rendimiento entre los dos no es significativa.

src: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx


15

Sí, el compilador no necesita pasar el thispuntero implícito a los staticmétodos. Incluso si no lo usa en su método de instancia, todavía se está pasando.


¿Cómo se relaciona esto con una ventaja de rendimiento o memoria en tiempo de ejecución?
Scott Dorman

11
Pasar un parámetro adicional significa que la CPU tiene que hacer un trabajo adicional para colocar ese parámetro en un registro y empujarlo a la pila si el método de instancia llama a otro método.
Kent Boogaart el

5

Será un poco más rápido ya que no se pasa este parámetro (aunque el costo de rendimiento de llamar al método es probablemente mucho más que este ahorro).

Diría que la mejor razón por la que puedo pensar en métodos estáticos privados es que significa que no puede cambiar accidentalmente el objeto (ya que no hay este puntero).


4

Esto le obliga a recordar que también debe declarar cualquier miembro con ámbito de clase que la función utilice también como estático, lo que debería ahorrar la memoria de crear esos elementos para cada instancia.


El hecho de que sea una variable de ámbito de clase no significa que deba ser estática.
Scott Dorman

3
No, pero si se usa con un método estático, DEBE ser estático. Si el método no era estático, entonces es posible que no haya hecho que el miembro de la clase sea estático, y eso generaría más memoria para cada instancia de la clase.
Joel Coehoorn

2

Prefiero que todos los métodos privados sean estáticos a menos que realmente no puedan serlo. Preferiría mucho lo siguiente:

public class MyClass
{
    private readonly MyDependency _dependency;

    public MyClass(MyDependency dependency)
    {
        _dependency = dependency;
    }

    public int CalculateHardStuff()
    {
        var intermediate = StepOne(_dependency);
        return StepTwo(intermediate);
    }

    private static int StepOne(MyDependency dependency)
    {
        return dependency.GetFirst3Primes().Sum();
    }

    private static int StepTwo(int intermediate)
    {
        return (intermediate + 5)/4;
    }
}

public class MyDependency
{
    public IEnumerable<int> GetFirst3Primes()
    {
        yield return 2;
        yield return 3;
        yield return 5;
    }
}

sobre cada método que accede al campo de instancia. ¿Por qué es esto? Debido a que este proceso de cálculo se vuelve más complejo y la clase termina con 15 métodos de ayuda privados, REALMENTE quiero poder llevarlos a una nueva clase que encapsule un subconjunto de los pasos de una manera semánticamente significativa.

Cuando MyClasstenemos más dependencias porque necesitamos iniciar sesión y también tenemos que notificar a un servicio web (disculpe los ejemplos cliché), entonces es realmente útil ver fácilmente qué métodos tienen qué dependencias.

Herramientas como R # le permite extraer una clase de un conjunto de métodos estáticos privados en unas pocas pulsaciones de teclas. Intente hacerlo cuando todos los métodos de ayuda privada estén estrechamente vinculados al campo de instancia y verá que puede ser un gran dolor de cabeza.


-3

Como ya se ha dicho, los métodos estáticos tienen muchas ventajas. Sin embargo; tenga en cuenta que vivirán en el montón durante la vida de la aplicación. Recientemente, pasé un día rastreando una pérdida de memoria en un Servicio de Windows ... la pérdida fue causada por métodos estáticos privados dentro de una clase que implementó IDisposable y fue llamada constantemente desde una declaración de uso. Cada vez que se creaba esta clase, la memoria se reservaba en el montón para los métodos estáticos dentro de la clase, desafortunadamente, cuando se eliminaba la clase, no se liberaba la memoria para los métodos estáticos. Esto provocó que la huella de memoria de este servicio consumiera la memoria disponible del servidor en un par de días con resultados predecibles.


44
Esto no tiene ningún sentido. El montón nunca almacena memoria para el código para ningún método, estático o de otro tipo. El montón es para instancias de objetos. Habrá datos en la pila para cualquier invocación de cualquier método (para mantener la memoria para los parámetros, el valor de retorno, los locales no izados, etc.) pero todo eso desaparece cuando el método termina de ejecutarse.
Servy
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.