2010-03-25 9 views
20

ho la seguente proprietàtest se una proprietà non è nullo prima di tornare

public MyType MyProperty {get;set;} 

voglio cambiare questa proprietà in modo che se il valore è nullo, sarà popolano prima il valore, e poi restituirlo ... ma senza utilizzando una variabile membro privata.

Per esempio, se stavo facendo questo:

public MyType MyProperty 
{ 
    get 
    { 
     if (_myProperty != null) 
      return _myProperty 
     else 
      _myProperty = XYZ; 
      return _myProperty; 
    } 
    set 
    { 
     _myProperty = value; 
    } 
} 

è possibile? O ho bisogno della variabile membro per averlo fatto?

+3

No. Non puoi avere la tua torta e mangiarla anche tu. –

+0

_ senza una variabile membro [privata] _... Mi hai perso! Oltre a fare affidamento su alcuni tipi di feed globali/esterni, una proprietà ha bisogno di alcune variabili su cui archiviare il suo stato. – mjv

+0

@mjv: No, non è esplicitamente. Con le proprietà automatiche (come nel primo snippet di codice) il compilatore genera il campo privato per te. – Thomas

risposta

29

È necessaria una variabile membro e una dichiarazione di proprietà completa. Le proprietà implementate automaticamente sono solo applicabili se sono involucri banali attorno a un campo, senza alcuna logica. È possibile semplificare il codice getter un po ', a proposito:

get 
{ 
    if (_myProperty == null) 
    { 
     _myProperty = XYZ; 
    } 
    return _myProperty; 
} 

(Si noti che tutto questo non è thread-safe senza blocco in più, ma suppongo che va bene.)

Tra l'altro, è già avete una variabile membro privata se stai usando le proprietà implementate automaticamente - è solo che il compilatore lo sta generando per te.

+2

La cosa divertente è che, poche settimane dopo aver postato la domanda, ho letto la tua spiegazione delle proprietà automatiche in C# in Profondità :-) Grazie Jon, continua così! – DaveDev

10

La cosa migliore che puoi fare è dargli un valore nel costruttore. So che in questo modo si perde il "caricamento lento", ma non si possono avere proprietà automatiche e caricamento pigro allo stesso tempo.

+4

Anche se è stato assegnato un valore nel costruttore, potrebbe (attualmente) essere ancora impostato su null altrove. Può * essere * più appropriato per assicurarsi che il valore sia impostato nel costruttore, ma questo riguarda davvero la semantica della proprietà piuttosto che il codice usato per implementarla. –

+0

@Jon: buon punto. Quindi fai in modo che il setter non permetta mai alla proprietà di essere nulla :) – galford13x

+0

@ galford13x: questo ti priverebbe anche della possibilità di usare le proprietà auto, tho –

0

è necessario il variabile membro per avere fatto:

public class MyClass 
{ 
    MyType _myProperty = null; 

    public MyType MyProperty 
    {  
     get 
     { 
      if(_myProperty == null) 
       _myProperty = XYZ; 

      return _myProperty; 
     } 
    } 
} 
+0

Quale parte di «senza utilizzare una variabile membro privata» considera la soluzione? – XpiritO

+1

La parte in cui dico che è necessaria una variabile membro privata perché Auto Properties non supporta ciò che vuole fare. –

+0

era quello nel post originale? Non pensare così ... – XpiritO

1

Stai andando ad avere bisogno di una variabile privata per implementare questo perché avete logica nei getter/setter.

0

Sì, è possibile. Ma devi implementarlo tu stesso, non con le proprietà automatiche. Le tue proprietà non hanno necessariamente bisogno di lavorare solo con le variabili membro sebbene questo sia l'impostazione predefinita.

Ricordare che le proprietà vengono effettivamente trasformate in metodi Getter e Setter e si può fare molto lavoro nel loro ambito. Sebbene questa pratica sia solitamente scoraggiata. Le buone pratiche affermano che l'accesso alla proprietà dovrebbe essere rapido e non bloccare il codice client per lunghi periodi di tempo.

Si potrebbe semplicemente fare questo:

public MyType MyProperty 
{ 
    get 
    { 
     if (_myProperty != null) 
      return _myProperty 
     else 
      return XYZ; 
    } 
    set 
    { 
     _myProperty = value; 
    } 
} 
+0

Com'è possibile? – galford13x

1

Se desiderate fare qualsiasi abbellimento sul ottenere o impostare il comportamento di un immobile, poi si perde la posizione di archiviazione generato dal compilatore, in modo da avere per memorizzare il valore da qualche parte da soli. Una variabile membro privata ha più senso, il più delle volte.

10
return _myProperty?? (_myProperty = XYZ); 
+0

Non molto buono. Se 'XYZ' è effettivamente:' FarFarAwayServer.DoReallyLongCalculation() 'ne soffrirai molto. Probabilmente intendevi: 'return _myProperty ?? (_myProperty = XYZ); '. Non mi piace, però. –

+0

Sì, voglio dire (_myProperty = XYZ). Grazie. Ma nel caso di FarFarAwayServer.DoReallyLongCalculation() soffrirà anche in altri modi, giusto? – malay

+0

Certo, ma solo una volta. Il tuo codice originale ne soffrirebbe sempre. –

0

Solo quando si utilizza una variabile membro.

Di solito, combino il caricamento lento con implementation of IDisposable, in modo che qualsiasi variabile da ripulire possa essere gestita nel metodo Dispose.

0

Per "variabile membro" presumo intendete una variabile definita all'interno della proprietà get.Sì, certamente non hai bisogno di una variabile definita localmente. Il modello più comune, che consente di risparmiare un linee copule di codice, è:

if (_myProperty == null) 
     _myProperty = XYZ; 

    return _myProperty; 

Se per "variabile membro" si intende un campo di supporto, allora sì, si ha bisogno uno. Solo la semplice relazione "pass through" del campo/proprietà può essere implementata senza creare esplicitamente un backing field. (E anche in questo caso, viene generato dal compilatore.) Per istanziare-se-null, devi definirlo esplicitamente.

4

tuo codice:

public MyType MyProperty {get;set;} 

fare riferimento a "Automatic Properties", che sono solo "zucchero sintattico", come si può verificare here.

il compilatore genera il campo per la proprietà e genera il codice nel Preparati per puntare al campo anche.

internal class ClassName 
{ 
    // Fields 
    [CompilerGenerated] 
    private MyType <Property>k__BackingField; 

    // Properties 
    public MyType MyProperty 
    { 
     [CompilerGenerated] 
     get 
     { 
      return this.<Property>k__BackingField; 
     } 
     [CompilerGenerated] 
     set 
     { 
      this.<Property>k__BackingField = value; 
     } 
    } 
} 

Quindi, il codice sempre essere sostenuta da un campo compilatore ha generato.

0

Se la proprietà è richiesta, alcuni controlli possono renderlo a prova di proiettile. Tendo ad usare qualcosa come:

public MyType MyProperty 
{ 
    get 
    { 
    if (_myProperty == null) 
     _myProperty == XYZ; 
    return _myProperty; 
    } 
    set 
    { 
    if(value == null) 
     throw InvalidArgumentException(); 
    _myProperty = value; 
    } 
} 

Rende anche il TDD più semplice.

0

Prova questa

Public Class MyClass 
{  
    Public MyType Alfa 
    { 
     If(this._Alfa == null) this.SetAlfa(); 
     return _Alfa; 
    } 

    private MyType _Alfa {get;set;} 

    private void SetAlfa() 
    { 
     //Somenthing to valorize _Alfa 
    }  
} 
1

propongo di prendere in considerazione l'utilizzo di Lazy initialization. Non sarà aiuterà ad evitare variabile membro così dispiaciuto per questo, ma che il codice vi aiuterà ad evitare la prenotazione di memoria per la variabile membro fino a quando la classe avrà bisogno di tale variabile:

public class MyType 
{ 
    public MyType() 
    { 
     XYZ(); 
    } 

    public void XYZ() 
    { 
     //some kind of initialization 
    } 
} 

public class TestType 
{ 
    private Lazy<MyType> _myProperty; 
    public MyType MyProperty 
    { 
     get { return _myProperty.Value; }//_myProperty will be null until some code will try to read it 
    } 

} 

Un'altra cosa da sottolineare o realtà per ricordare, non sarai in grado di essere assolutamente senza variabile membro. Perché dietro le tende. Il compilatore net creerà quella variabile membro al posto tuo. Semplicemente non ti notificherà questo passaggio. Ma come è stato menzionato da altri, se guardi in MSIL generato, vedrai quella variabile membro creata per te.

Problemi correlati