Frequenza dell'accesso getter

2

Poiché i getter di C # possono essere relativamente costosi, mi chiedo se verranno chiamati ogni volta o se il compilatore farà qualche ottimizzazione.

Diamo un'occhiata a questo:

List<A> CurrentList{ get; }

void DoSomethingWithList()
{
    if(CurrentList.Count > 42)
    {        
        foreach(A processingA in CurrentList)
        {
            A.DoSomething();
        }
    }
}

Il getter "CurrentList" verrà chiamato realmente due volte?

    
posta BooleanAssange 26.10.2016 - 12:05
fonte

5 risposte

7

Non so molto sull'ottimizzazione del getter della proprietà, ma la risposta di Pete sembra coprire adeguatamente l'argomento. Essenzialmente, poiché un getter non è altro che zucchero sintattico per un metodo Getter, allora si possono fare pochissime garanzie sulla sua esecuzione e, successivamente, non è sempre possibile utilizzare ottimizzazioni come Memoization.

Ma ancora più importante

Se le tue proprietà sono costose, allora stai sbagliando. L'utilizzo di getter dovrebbe essere economico e non dovrebbe modificare lo stato dell'oggetto. Se scopri che hai un getter che viola uno di questi punti, in realtà dovrebbe essere un metodo .

    
risposta data 26.10.2016 - 12:32
fonte
5

Viene chiamato due volte in generale - è sufficiente implementare il getter per incrementare un contatore ogni volta che viene chiamato ed eseguire il codice. Il compilatore non conosce la differenza tra la tua proprietà e quella che cambierà stato in ogni chiamata, non più di quanto avverrebbe se stesse chiamando un metodo sull'oggetto. Se la proprietà è automatica o è un semplice accesso al campo (e possibilmente per altri casi semplici), il compilatore può inline e quindi potrebbe finire per essere ottimizzato per un singolo accesso se non esistono barriere tra gli usi.

Esegui le tue ottimizzazioni per memorizzare nella cache il risultato (nel codice client o nel getter) oppure non utilizzare le proprietà per costosi calcoli.

    
risposta data 26.10.2016 - 12:23
fonte
0

Se hai appena tracciato in Debug lo vedresti chiamato
Ottenere non è così costoso Ma puoi fare riferimento direttamente a un campo di supporto

    List<int> currentList = new List<int>() { 1 };
    List<int> CurrentList { get { return currentList; } }
    void DoSomethingWithList()
    {
        if (currentList.Count > 42)
        {
            foreach (int processingA in currentList)
            {
                //A.DoSomething();
            }
        }
    }
    
risposta data 16.11.2016 - 16:54
fonte
0

La chiamata getter non verrà memorizzata nella cache ma potrebbe ottenere inline . Poiché il codice all'interno della chiamata getter è semplicemente un campo letto, l'inline del codice avrebbe un effetto simile sulle prestazioni di una cache e avrebbe il vantaggio che eventuali effetti collaterali sarebbero riprodotti fedelmente.

Se il getter ha eseguito più logica rispetto alla semplice restituzione di un campo, è meno probabile che venga reso in linea.

Non puoi forzare un getter ad essere inline, ma puoi incoraggiarlo, in questo modo:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
List<int> CurrentList { get { return currentList; } }

Vedi anche questa risposta e questa risposta .

    
risposta data 27.02.2017 - 21:12
fonte
-1

Getter in C # è solo un metodo speciale che restituisce un valore, non più o meno. Quindi se hai bisogno di chiamare il metodo due volte, sarà sicuramente usato due volte.

Nel tuo esempio specifico, la prima chiamata per ottenere il Conteggio, la seconda chiamata per scorrere tutti gli elementi del valore restituito (che è un Elenco).

Se esiste un campo di supporto per la tua proprietà, la prima chiamata che ottiene Count non farebbe nulla di costoso o considerevole, il Count è sempre lì per l'accesso rapido.

Tuttavia, se la tua proprietà crea sempre un nuovo List<A> su ogni accesso, qualcosa del genere:

List<A> CurrentList {
    get {
       return new List<A>(....);
    }
}

Quindi potrebbe essere qualcosa di sbagliato con il tuo codice qui. In questo caso, è necessario ottenere l'elenco prima di fare qualsiasi cosa sul risultato restituito (ottenendo Count e ciclicamente attraverso tutti gli elementi), in questo modo:

void DoSomethingWithList() {
  var list = CurrentList;
  if(list.Count > 42)
  {        
    foreach(A processingA in list)
    {
        processingA.DoSomething();
    }
  }
}

Ancora una volta vorrei sottolineare che se si utilizza un campo di supporto per la tua proprietà, il tuo codice dovrebbe andare bene (e non può essere diverso per essere migliore). Tutto ciò che inserisci nella chiusura di get darà come risultato un metodo getter come questo:

List<A> getMethod(){
    return new List<A>(....);
}

Niente di speciale qui, la proprietà è solo un involucro del metodo getter e setter. Invece di usare 2 metodi separati, possiamo semplicemente usare 1 proprietà e usare = intuitivamente. In un altro punto di vista, Property ha l'aspetto di un wrapper attorno ad un backing field (in alcuni casi, poiché alcune proprietà non hanno un backing field), quindi aggiunge un altro layer logico al punto di accesso del backing field (come il controllo del differenza tra il nuovo valore e il valore corrente del campo di supporto per aumentare alcuni eventi PropertyChanged, ...).

    
risposta data 28.10.2016 - 12:40
fonte

Leggi altre domande sui tag