Vantaggi dell'uso di metodi statici privati


209

Quando si crea una classe con metodi privati ​​interni, di solito per ridurre la duplicazione del codice, che non richiede l'uso di campi di istanza, ci sono vantaggi in termini di prestazioni o memoria nel dichiarare il metodo come statico?

Esempio:

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;
}

C'è qualche vantaggio nel dichiarare i metodi GetInnerXml () come statici? Nessuna risposta d'opinione per favore, ho un'opinione.


Risposte:


221

Dalla pagina della regola FxCop su questo:

Dopo aver contrassegnato i metodi come statici, il compilatore emetterà siti di chiamata non virtuali a questi membri. L'emissione di siti di chiamata non virtuali impedirà un controllo in fase di esecuzione per ogni chiamata che garantisce che il puntatore dell'oggetto corrente sia non nullo. Ciò può comportare un aumento delle prestazioni misurabile per il codice sensibile alle prestazioni. In alcuni casi, il mancato accesso all'istanza dell'oggetto corrente rappresenta un problema di correttezza.


37
Vorrei anche aggiungere che una clausola "statica" non danneggia e fornisce già un po 'di "documentazione" con 1 parola. Ti dice che questo metodo non utilizza alcun membro dell'istanza e ottieni questa documentazione quasi gratuitamente
frandevel,

20
Andrei fino al punto di dire: "Se un metodo non ha bisogno dell'accesso allo stato (questo), rendilo statico" come regola generale.
DanMan

3
Nell'interesse dell'equilibrio, vale la pena sottolineare che molte persone sono generalmente contrarie ai metodi statici perché infrangono il polimorfismo e significano che l'oggetto non può essere testato. ad esempio, vedi googletesting.blogspot.co.uk/2008/12/…
Andy,

@ Andy - Buon punto. Un modo per tracciare la linea sarebbe quello di vedere se il metodo statico accede a qualcosa al di fuori dei parametri che passi. Fintanto che è autonomo in questo modo, dovrebbe essere facile da testare e non è necessario per stubare qualsiasi cosa.
Neil

4
Molti sviluppatori non hanno familiarità con "statica privata". L'ho usato nella base di codice comune del mio team e ha creato confusione. In cambio, offre un vantaggio molto minore. Potremmo scegliere di educare tutti i membri del team, compresi tutti i futuri sviluppatori che mantengono il codice, su cosa significhi. Ma il vantaggio di passare da un metodo privato a uno statico privato è così minore (cioè rimuovere la dipendenza dai dati dell'istanza), non vale la pena lo sforzo e la confusione. Il metodo è già di ambito privato in entrambi i casi. È una stranezza linguistica che non è davvero necessario conoscere.
Curtis Yallop,

93

Quando scrivo una classe, la maggior parte dei metodi rientra in due categorie:

  • Metodi che utilizzano / modificano lo stato dell'istanza corrente.
  • Metodi di supporto che non usano / cambiano lo stato dell'oggetto corrente, ma mi aiutano a calcolare i valori di cui ho bisogno altrove.

I metodi statici sono utili, perché solo osservando la sua firma, sai che la chiamata non utilizza o modifica lo stato dell'istanza corrente.

Prendi questo esempio:

Biblioteca di classe pubblica
{
    Trova libro statico privato (Elenco libri <Libro>, titolo stringa)
    {
        // il codice va qui
    }
}

Se un'istanza dello stato della biblioteca viene rovinata, e sto cercando di capire perché, posso escludere findBook come colpevole, proprio dalla sua firma.

Cerco di comunicare il più possibile con la firma di un metodo o di una funzione, e questo è un modo eccellente per farlo.


1
Tipo di dichiarazione const-method in C ++, no?
anhoppe,

Sì, questo è un altro buon modo di usare il linguaggio per semplificare le cose limitando ciò che potrebbe andare storto.
Neil

Questo non è necessariamente vero. Supponiamo che a Libraryabbia un campo di istanza List<Book> _booksper memorizzare i suoi libri (non come Libraryprobabilmente progetteresti una classe ma w / e), e passa questo elenco a findBook, e che il metodo statico chiama books.Clear()o books.Reverse()così via. Se dai a un metodo statico l'accesso a un riferimento a uno stato mutabile, quel metodo statico può benissimo rovinare il tuo stato.
Sara,

1
Vero. E in quel caso, la firma ci mostrerebbe che questo metodo aveva accesso a (e la possibilità di mutare) un'istanza di Library.
Neil,

Per praticamente qualsiasi costrutto protettivo che potremmo usare, c'è un modo per minarlo. Ma usarli è ancora saggio e ci aiuta a spingerci nella giusta direzione, verso la "fossa del successo".
Neil,

81

Una chiamata a un metodo statico genera un'istruzione call nel linguaggio intermedio Microsoft (MSIL), mentre una chiamata a un metodo di istanza genera un'istruzione callvirt, che verifica anche la presenza di riferimenti a oggetti null. Tuttavia, il più delle volte la differenza di prestazioni tra i due non è significativa.

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


15

Sì, il compilatore non ha bisogno di passare il thispuntatore implicito ai staticmetodi. Anche se non lo usi nel tuo metodo di istanza, viene comunque passato.


In che modo ciò si riferisce a un vantaggio in termini di prestazioni o memoria in fase di esecuzione?
Scott Dorman,

11
Passare un parametro aggiuntivo significa che la CPU deve fare un lavoro extra per posizionare quel parametro in un registro e inserirlo nello stack se il metodo di istanza chiama un altro metodo.
Kent Boogaart,

5

Sarà leggermente più veloce in quanto non viene passato questo parametro (anche se il costo delle prestazioni per chiamare il metodo è probabilmente molto più di questo risparmio).

Direi che il miglior motivo a cui riesco a pensare per i metodi statici privati ​​è che significa che non puoi cambiare accidentalmente l'oggetto (dato che non c'è questo puntatore).


4

Questo ti costringe a ricordare di dichiarare anche tutti i membri con ambito di classe utilizzati dalla funzione come statici, il che dovrebbe salvare la memoria della creazione di quegli elementi per ogni istanza.


Solo perché è una variabile con ambito di classe non significa che dovrebbe essere statico.
Scott Dorman,

3
No, ma se viene utilizzato da un metodo statico, DEVE essere statico. Se il metodo non fosse statico, potresti non aver reso statico il membro della classe e ciò avrebbe comportato l'utilizzo di più memoria per ogni istanza della classe.
Joel Coehoorn,

2

Preferisco di gran lunga che tutti i metodi privati ​​siano statici a meno che non possano davvero esserlo. Preferirei di gran lunga quanto segue:

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;
    }
}

su ogni metodo che accede al campo dell'istanza. Perchè è questo? Perché quando questo processo di calcolo diventa più complesso e la classe finisce con 15 metodi di supporto privati, allora VERAMENTE voglio essere in grado di estrarli in una nuova classe che incapsula un sottoinsieme dei passaggi in modo semanticamente significativo.

Quando si MyClassottengono più dipendenze perché è necessario il log e occorre anche avvisare un servizio Web (si prega di scusare gli esempi di cliché), è davvero utile vedere facilmente quali metodi hanno quali dipendenze.

Strumenti come R # ti consentono di estrarre una classe da una serie di metodi statici privati ​​in pochi tasti. Prova a farlo quando tutti i metodi di supporto privati ​​sono strettamente associati al campo dell'istanza e vedrai che può essere piuttosto un mal di testa.


-3

Come è già stato affermato, i metodi statici presentano numerosi vantaggi. Però; tieni presente che vivranno sul mucchio per la vita dell'applicazione. Di recente ho trascorso un giorno a rintracciare una perdita di memoria in un servizio di Windows ... la perdita era causata da metodi statici privati ​​all'interno di una classe che implementava IDisposable e veniva costantemente chiamata da un'istruzione using. Ogni volta che questa classe veniva creata, la memoria veniva riservata sull'heap per i metodi statici all'interno della classe, sfortunatamente, quando la classe veniva eliminata, la memoria per i metodi statici non veniva rilasciata. Ciò ha causato il footprint di memoria di questo servizio di consumare la memoria disponibile del server entro un paio di giorni con risultati prevedibili.


4
Questo non ha alcun senso. L'heap non archivia mai la memoria per il codice per alcun metodo, statico o di altro tipo. L'heap è per istanze di oggetti. Ci saranno dati nello stack per qualsiasi invocazione di qualsiasi metodo (per contenere la memoria per i parametri, il valore di ritorno, i locali non montati, ecc.) Ma tutto ciò scompare quando il metodo termina l'esecuzione.
Servito il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.