2015-01-12 21 views
45

Nel C# 6, è possibile semplificare l'implementazione di una proprietà utilizzando una proprietà auto solo getter. Ad esempio, se fossi l'attuazione del astratta Stream classe:Qual è la differenza tra proprietà auto solo getter e proprietà body expression?

public override bool CanRead { get; } = true; 

Comunque è anche possibile scrivere con un corpo di espressione, anche di nuovo in C# 6:

public override bool CanRead => true; 

Qual è la differenza tra i due e quando dovrei usare l'una o l'altra?

risposta

51

Sono zucchero sintattico per due cose diverse. Il primo inizializza un campo di supporto e lo imposta nell'espressione a destra del compito durante l'inizializzazione del campo. Quest'ultimo crea un get che fa esattamente ciò che è nell'espressione.

public override bool CanRead { get; } = true; 

è equivalente a

private readonly bool __backingFieldCanRead = true; 

public override bool CanRead 
{ 
    get 
    { 
     return __backingFieldCanRead; 
    } 
} 

Questo

public override bool CanRead => true; 

è equivalente a

public override bool CanRead 
{ 
    get 
    { 
     return true; 
    } 
} 

Si comportano in modo diverso. Il primo caso imposta il valore della proprietà quando viene creato l'oggetto e il campo viene inizializzato, l'altro caso valuta l'espressione ogni volta che viene richiamato il getter della proprietà. Nel caso semplice di un bool, il comportamento è lo stesso. Tuttavia se l'espressione causa effetti collaterali, le cose sono diverse. Considerare questo esempio:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var fooBar1 = new FooBar(); 
     Console.WriteLine(fooBar1.Baz); 
     Console.WriteLine(fooBar1.Baz); 
     var fooBar2 = new FooBar(); 
     Console.WriteLine(fooBar2.Baz); 
     Console.WriteLine(fooBar2.Baz); 
    } 
} 

public class FooBar 
{ 
    private static int counter; 
    public int Baz => counter++; 
} 

Qui, "0, 1, 2, 3" vengono stampati. Il campo statico viene incrementato ogni volta che viene richiamato il getter della proprietà. Tuttavia, con un inizializzatore struttura:

public int Baz { get; } = counter++; 

Poi "0, 0, 1, 1" viene stampato perché l'espressione viene valutata nel costruttore dell'oggetto.

+1

Tecnicamente nel primo caso il campo di backing generato non è anche 'readonly'? – Kyle

+5

Il campo di supporto viene assegnato come se fosse assegnato nell'inizializzatore del campo, non nel corpo del costruttore. È possibile osservare questa differenza se la classe base chiama un metodo virtuale, che si verifica prima dell'esecuzione del corpo del costruttore. È una sottile differenza, ammettiamolo :) –

+1

@JonSkeet Oh, hai ragione, il campo è "initonly". – vcsjones

0

Nel caso si descrive nel nostro esempio, ho usato a preferire:

public override bool CanRead { get; } = true; 

Ma oggi ho segnalato che questa implementazione causano un'allocazione di memoria per il campo di supporto. E così, questa implementazione: bool CanRead => true; può salvare 4 byte.

Problemi correlati