Qual è la differenza tra un campo e una proprietà?


1130

In C #, cosa rende un campo diverso da una proprietà e quando deve essere usato un campo invece di una proprietà?


32
Microsoft risponde direttamente a questa domanda (per tutti i linguaggi .NET) come parte delle Linee guida per la progettazione dei membri . Per i dettagli vedere gli articoli Design della proprietà e Field Design . Si noti che esiste una distinzione tra membri di istanza e membri statici .
DavidRR

Risposte:


979

Le proprietà espongono i campi. I campi dovrebbero (quasi sempre) essere riservati a una classe e accessibili tramite get e set properties. Le proprietà forniscono un livello di astrazione che consente di modificare i campi senza influire sul modo in cui sono accessibili dalle cose che usano la classe.

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kent sottolinea che le Proprietà non sono necessarie per incapsulare i campi, potrebbero fare un calcolo su altri campi o servire ad altri scopi.

@GSS sottolinea che è anche possibile eseguire altre logiche, come la convalida, quando si accede a una proprietà, un'altra utile funzione.


185
Vale la pena notare che le proprietà non sono necessarie per incapsulare i campi. Non ci potrebbe essere alcun campo dietro la proprietà. Potrebbe essere un calcolo o restituire una costante o altro.
Kent Boogaart,

9
"pur non influenzando il modo in cui sono accessibili dalle cose che usano la tua classe." perdonatemi se capisco erroneamente, quindi, ma perché la necessità di modificatori di accesso davanti alle proprietà, se il campo dietro sembra gestirlo? cioè perché rendere una proprietà qualcosa di diverso dal pubblico?
Chucky,

18
La tua risposta è stata subito prima delle modifiche e dei commenti errati con voti strani. Una proprietà deve sempre incapsulare uno o più campi e non deve mai eseguire operazioni di sollevamento o convalida. Se hai bisogno di una proprietà come UserName o Password per avere la convalida, cambia il loro tipo da stringhe a Oggetti valore . C'è un contratto non scritto tra un creatore di classe e il consumatore. I campi mantengono lo stato, le proprietà espongono lo stato usando uno o più campi, i vuoti cambiano stato (sollevamento pesante) e le funzioni eseguono query (sollevamento pesante).
Suamere,

6
@jpaugh Se sono un consumatore di classe, seguo i contratti stabiliti dal creatore della classe. Se una proprietà è string, il mio contratto è: assegnare qualsiasi carattere fino a ~ 2bil lunghezza. Se una proprietà è DateTime, il mio contratto è: assegnare qualsiasi numero entro i limiti di DateTime, che posso cercare. Se il creatore aggiunge vincoli ai setter, tali vincoli non vengono comunicati. Ma se, invece, il creatore cambia il tipo da stringa Surname, allora la loro nuova classe Cognome comunica i vincoli e la proprietà public Surname LastNamenon ha la validazione del setter. Inoltre, Surnameè riutilizzabile.
Suamere,

4
E poiché Surname, nel mio esempio, è riutilizzabile, non è necessario preoccuparsi in seguito di copiare / incollare quelle convalide in un setter di proprietà in altre posizioni nel codice. Né mi chiedo se la convalida di un cognome sia in più punti se mai dovessi apportare modifiche alle regole aziendali per i cognomi.
Dai

261

I principi di programmazione orientata agli oggetti affermano che il funzionamento interno di una classe dovrebbe essere nascosto al mondo esterno. Se esponi un campo, stai essenzialmente esponendo l'implementazione interna della classe. Pertanto avvolgiamo i campi con Proprietà (o metodi nel caso di Java) per darci la possibilità di modificare l'implementazione senza interrompere il codice a seconda di noi. Dal momento che possiamo mettere la logica nella proprietà, ci consente anche di eseguire la logica di convalida ecc. Se ne abbiamo bisogno. C # 3 ha l'idea forse confusa di autoproperties. Questo ci consente di definire semplicemente la proprietà e il compilatore C # 3 genererà il campo privato per noi.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}

89
+1 per la menzione di autoproperties - Penso che questo sia qualcosa che molte delle risposte qui (e altrove) hanno dimenticato di portare. Senza questa spiegazione, può ancora essere abbastanza difficile capire cosa public int myVar { get; set; }rappresenta davvero (e presumo che sia la ragione per almeno il 50% dei risultati ottenuti da questa domanda).
Priidu Neemre,

7
+1 anche per menzionare auto e menzionare come funziona ("AutoProperty genera campo privato per noi") Questa è stata la risposta che stavo cercando per una domanda che avevo. Durante la ricerca non ho visto sulla pagina di MSDN su di loro alcuna indicazione che un campo privato fosse stato creato e causasse confusione. Immagino sia questo che significa? "Gli attributi sono consentiti nelle proprietà implementate automaticamente ma ovviamente non nei campi di supporto poiché non sono accessibili dal codice sorgente. Se è necessario utilizzare un attributo nel campo di supporto di una proprietà, è sufficiente creare una proprietà normale." ma non ne ero sicuro.
Nyra,

3
Nota che l'esempio dato non incapsula lo squat. Questa proprietà offre il 100% di accesso completo al campo privato, quindi non è affatto orientato agli oggetti. Potresti anche avere un campo pubblico in questo caso. Certo, aiuta (marginalmente) a refactificare il codice in futuro, ma qualsiasi IDE degno del suo coraggio può trasformare un campo in una proprietà con pochi tasti. La risposta potrebbe essere tecnicamente corretta su come funzionano le proprietà, ma non fornisce una buona "spiegazione OOP" ai loro usi.
Sara

2
@kai Sono d'accordo sul fatto che la risposta sia troppo semplificata e non mostri tutto il potere di un'auto-proprietà, tuttavia non sono d'accordo sul fatto che questo non sia orientato agli oggetti. Potresti voler controllare la differenza tra campi e proprietà . I campi non possono essere virtuali ed virtualè esso stesso parte della programmazione orientata agli oggetti.
Gobe,

Certo, ci sono alcune differenze funzionali. Non chiamerei virtualOOP in sé però. È uno strumento che abilita il polimorfismo, che è uno degli strumenti chiave che ABILITANO OOP. Non è OOP in sé e per sé, e non c'è nulla intrinsecamente OOP su un'autopropria pubblica. Non conterrei nemmeno cose come la riflessione o l'individuazione in banca dati di OOP. Normalmente non sarei così pedante al riguardo, ma la risposta menzionava specificamente i principi OO come la forza motrice dietro l'esempio di codice, e non sono d'accordo.
Sara,

164

Una differenza importante è che le interfacce possono avere proprietà ma non campi. Questo, per me, sottolinea che le proprietà dovrebbero essere usate per definire l'interfaccia pubblica di una classe mentre i campi sono pensati per essere usati nel funzionamento interno privato di una classe. Di norma creo raramente campi pubblici e allo stesso modo creo raramente proprietà non pubbliche.


98

Ti darò un paio di esempi sull'uso delle proprietà che potrebbero far girare gli ingranaggi:

  • Inizializzazione lenta : se si possiede una proprietà di un oggetto che è costoso da caricare, ma non si accede così tanto nelle normali esecuzioni del codice, è possibile ritardarne il caricamento tramite la proprietà. In questo modo, è semplicemente seduto lì, ma la prima volta che un altro modulo tenta di chiamare quella proprietà, controlla se il campo sottostante è nullo - se lo è, va avanti e lo carica, sconosciuto al modulo chiamante. Ciò può accelerare notevolmente l'inizializzazione degli oggetti.
  • Tracciamento sporco: di cui ho effettivamente appreso dalla mia domanda qui su StackOverflow. Quando ho molti oggetti i cui valori potrebbero essere cambiati durante una corsa, posso usare la proprietà per tracciare se devono essere salvati nel database o meno. Se non è stata modificata una singola proprietà di un oggetto, il flag IsDirty non verrà attivato e pertanto la funzionalità di salvataggio verrà ignorata al momento di decidere cosa deve essere ripristinato nel database.

1
Una domanda sul tracking sporco: cosa succede se potessi cambiare direttamente il campo - non so se ciò può essere fatto, potrei dire: "l'oggetto non ha bisogno di essere salvato se non è cambiato un singolo CAMPO di un oggetto" quindi il tracking sporco non farebbe differenza, mi sto perdendo qualcosa?
siti dal

2
@juanpastas: il vantaggio delle proprietà per quanto riguarda il tracking sporco è che se i setter di proprietà impostano un flag "sporco", nello scenario in cui il flag non è impostato il codice non dovrà ispezionare i valori di alcuna proprietà per vedere se potrebbero essere cambiati. Al contrario, se un oggetto espone i suoi attributi come campi, il contenuto di tutti i campi deve essere confrontato con il valore precedente (che non solo aggiunge tempo per fare il confronto, ma significa anche che il codice deve avere il valore precedente).
supercat,

Questi sono buoni Ti permette anche di attivare metodi (come eventi) o di registrare quando il valore è impostato o letto.
coloboxp,

54

Utilizzando Proprietà, è possibile generare un evento quando viene modificato il valore della proprietà (ovvero PropertyChangedEvent) o prima che il valore venga modificato per supportare la cancellazione.

Questo non è possibile con i campi (accesso diretto a).

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}

3
Ho impiegato molto tempo per trovarlo. Questo è un MVVM . Grazie ! :)

46

Dal momento che molti di loro hanno spiegato con pro e contro tecnici di Propertiese Field, è tempo di entrare in esempi in tempo reale.

1. Proprietà consente di impostare il livello di accesso di sola lettura

Considera il caso di dataTable.Rows.Counte dataTable.Columns[i].Caption. Vengono dalla classe DataTableed entrambi sono pubblici per noi. La differenza nel loro livello di accesso è che non possiamo impostare il valore dataTable.Rows.Countma possiamo leggere e scrivere dataTable.Columns[i].Caption. È possibile attraverso Field? No!!! Questo può essere fatto Propertiessolo con .

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. Proprietà in PropertyGrid

Potresti aver lavorato con ButtonVisual Studio. Le sue proprietà sono mostrate in modo PropertyGridsimile Text, Nameecc. Quando trasciniamo un pulsante e quando facciamo clic sulle proprietà, troverà automaticamente la classe Buttone i filtri Propertiese la mostrerà in PropertyGrid(dove PropertyGridnon verranno mostrati Fieldanche se sono pubblici).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

In PropertyGrid, le proprietà Namee Textverranno mostrate, ma non SomeProperty. Perché??? Perché le proprietà possono accettare gli attributi . Non viene mostrato nel caso in cui [Browsable(false)]sia falso.

3. Può eseguire istruzioni all'interno di Proprietà

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4. Solo le proprietà possono essere utilizzate nell'origine vincolante

Binding Source ci aiuta a ridurre il numero di righe di codice. Fieldsnon sono accettati da BindingSource. Dovremmo usare Propertiesper quello.

5. Modalità di debug

Considera che stiamo usando Fieldper contenere un valore. Ad un certo punto è necessario eseguire il debug e verificare dove il valore sta diventando nullo per quel campo. Sarà difficile fare dove il numero di righe di codice è superiore a 1000. In tali situazioni possiamo usare Propertye impostare la modalità di debug all'interno Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }

Questi sono fatti interessanti, ma ti manca il punto di campi e la filosofia delle proprietà.
David Ferenczy Rogožan,

Cosa intendi con FILISOFIA ? @Dawid Ferenczy
Sarath Avanavu,

Vedi ad esempio la risposta contrassegnata. Ma hai notato che stai solo fornendo esempi di utilizzo, poiché la differenza tra campi e proprietà era già stata descritta, quindi
hai

2
Leggi la mia prima frase nella mia risposta. Ho detto espressamente che non ripeterò di nuovo tutto qui. Non ha senso!!! Le persone prima guarderanno prima la descrizione, poi gli esempi. La risposta contrassegnata fornisce bene la descrizione, ma ho aggiunto alcuni scenari ed esempi in tempo reale che hanno senso. Assicurati di pensare dal punto di vista del lettore prima di commentare @Dawid Ferenczy
Sarath Avanavu il

1
L'ho letto, ma ovviamente non hai letto il mio commento precedente: " Ma hai notato che stai solo fornendo esempi di utilizzo, poiché la differenza tra campi e proprietà era già stata descritta, quindi hai dimenticato il mio commento, per favore :) " .
David Ferenczy Rogožan,

32

DIFFERENZE - USI (quando e perché)

Un campo è una variabile dichiarata direttamente in una classe o struttura. Una classe o struttura può avere campi di istanza o campi statici o entrambi. In generale, è necessario utilizzare i campi solo per variabili con accessibilità privata o protetta . I dati che la tua classe espone al codice client devono essere forniti tramite metodi, proprietà e indicizzatori. Utilizzando questi costrutti per l'accesso indiretto ai campi interni, è possibile proteggersi da valori di input non validi.

Una proprietà è un membro che fornisce un meccanismo flessibile per leggere, scrivere o calcolare il valore di un campo privato. Le proprietà possono essere utilizzate come se fossero membri di dati pubblici, ma in realtà sono metodi speciali chiamati accessori . Ciò consente di accedere facilmente ai dati e aiuta ancora a promuovere la sicurezza e la flessibilità dei metodi . Le proprietà consentono a una classe di esporre un modo pubblico di ottenere e impostare valori, nascondendo al contempo il codice di implementazione o di verifica. Un accessor di proprietà get viene utilizzato per restituire il valore della proprietà e un accessor set viene utilizzato per assegnare un nuovo valore.


Questa è una risposta fantastica, mi ha davvero aiutato a capirlo.
Steve Bauman,

14

Le proprietà hanno il vantaggio principale di consentire all'utente di modificare il modo in cui si accede ai dati su un oggetto senza interrompere la sua interfaccia pubblica. Ad esempio, se è necessario aggiungere ulteriore convalida o modificare un campo memorizzato in un calcolato, è possibile farlo facilmente se il campo è stato inizialmente esposto come proprietà. Se hai appena esposto direttamente un campo, allora dovresti cambiare l'interfaccia pubblica della tua classe per aggiungere la nuova funzionalità. Tale modifica interromperebbe i client esistenti, richiedendo che fossero ricompilati prima che potessero utilizzare la nuova versione del codice.

Se scrivi una libreria di classi progettata per un largo consumo (come .NET Framework, che viene utilizzato da milioni di persone), questo può essere un problema. Tuttavia, se stai scrivendo una classe utilizzata internamente all'interno di una piccola base di codice (diciamo <= 50 K righe), non è davvero un grosso problema, perché nessuno sarebbe influenzato negativamente dalle tue modifiche. In tal caso, si tratta solo di preferenze personali.


11

Le proprietà supportano l'accesso asimmetrico, ovvero puoi avere un getter e un setter o solo uno dei due. Allo stesso modo le proprietà supportano l'accessibilità individuale per getter / setter. I campi sono sempre simmetrici, ovvero è sempre possibile ottenere e impostare il valore. Eccezione a ciò sono i campi di sola lettura che ovviamente non possono essere impostati dopo l'inizializzazione.

Le proprietà possono essere eseguite per un tempo molto lungo, avere effetti collaterali e persino generare eccezioni. I campi sono veloci, senza effetti collaterali e non genereranno mai eccezioni. A causa di effetti collaterali, una proprietà può restituire un valore diverso per ogni chiamata (come nel caso di DateTime.Now, ovvero DateTime.Now non è sempre uguale a DateTime.Now). I campi restituiscono sempre lo stesso valore.

I campi possono essere utilizzati per i parametri out / ref, le proprietà no. Le proprietà supportano una logica aggiuntiva: potrebbe essere utilizzata per implementare il caricamento lento tra le altre cose.

Le proprietà supportano un livello di astrazione incapsulando qualunque cosa significhi ottenere / impostare il valore.

Usa le proprietà nella maggior parte dei casi, ma cerca di evitare gli effetti collaterali.


I campi possono avere tutti i problemi di costo delle proprietà quando il tipo di dati del campo è un oggetto con un sovraccarico dell'operatore di conversione - è un sottile problema.
Andy Dent,

1
Le proprietà non dovrebbero mai avere effetti collaterali. Anche il debugger presume che possa valutarli in modo sicuro.
Craig Gidney,

@Strilanc: sono completamente d'accordo, tuttavia, non è sempre così. Per quanto riguarda il debugger, ci sono molti problemi con FuncEval se questo è ciò di cui stai parlando.
Brian Rasmussen,

11

Sullo sfondo una proprietà viene compilata in metodi. Quindi una Nameproprietà viene compilata in get_Name()e set_Name(string value). Puoi vederlo se studi il codice compilato. Quindi c'è un sovraccarico (molto) di prestazione quando li si usa. Normalmente userete sempre una Proprietà se esponete un campo verso l'esterno e lo userete spesso internamente se dovrete effettuare la validazione del valore.


7

Quando si desidera che la propria variabile privata (campo) sia accessibile all'oggetto della propria classe da altre classi, è necessario creare proprietà per tali variabili.

ad esempio se ho variabili denominate "id" e "name" che sono private ma potrebbero esserci situazioni in cui questa variabile era necessaria per l'operazione di lettura / scrittura al di fuori della classe. In quella situazione, la proprietà può aiutarmi a ottenere quella variabile da leggere / scrivere a seconda del get / set definito per la proprietà. Una proprietà può essere sia readonly / writeonly / readwrite entrambe.

ecco la demo

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}

6

La seconda domanda qui, "quando un campo dovrebbe essere usato al posto di una proprietà?", Viene trattata solo brevemente in questa altra risposta e anche in questo , ma non in molti dettagli.

In generale, tutte le altre risposte sono esatte su un buon design: preferire esporre le proprietà piuttosto che esporre i campi. Anche se probabilmente non ti ritroverai regolarmente a dire "wow, immagina quanto sarebbero peggiori le cose se avessi fatto di questo un campo anziché una proprietà", è molto più raro pensare a una situazione in cui diresti "wow, grazie a Dio ho usato un campo qui invece di una proprietà ".

Ma c'è un vantaggio che i campi hanno rispetto alle proprietà, ed è la loro capacità di essere usati come parametri "ref" / "out". Supponiamo di avere un metodo con la seguente firma:

public void TransformPoint(ref double x, ref double y);

e supponiamo che tu voglia usare quel metodo per trasformare un array creato in questo modo:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

Ecco il modo più veloce per farlo, dato che X e Y sono proprietà:

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

E sarà abbastanza buono! A meno che tu non abbia misure che dimostrino il contrario, non c'è motivo di fare una puzza. Ma credo che non sia tecnicamente garantito per essere veloce come questo:

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

Effettuando alcune misurazioni da solo, la versione con campi richiede circa il 61% delle volte rispetto alla versione con proprietà (.NET 4.6, Windows 7, x64, modalità di rilascio, nessun debugger collegato). Più costoso TransformPointdiventa il metodo, meno pronunciata diventa la differenza. Per ripeterlo tu stesso, corri con la prima riga commentata e con essa non commentata.

Anche se non ci sono stati benefici in termini di prestazioni per quanto sopra, ci sono altri posti in cui poter usare i parametri ref e out potrebbe essere utile, come quando si chiama la famiglia di metodi Interlocked o Volatile . Nota: se questo è nuovo per te, Volatile è sostanzialmente un modo per ottenere lo stesso comportamento fornito dalla volatileparola chiave. In quanto tale, come volatile, non risolve magicamente tutti i problemi di sicurezza dei thread come suggerisce il nome.

Sicuramente non voglio sembrare che sto sostenendo che tu vada "oh, dovrei iniziare a esporre i campi invece delle proprietà". Il punto è che se è necessario utilizzare regolarmente questi membri nelle chiamate che accettano parametri "ref" o "out", in particolare su qualcosa che potrebbe essere un tipo di valore semplice che difficilmente avrà mai bisogno di uno qualsiasi degli elementi a valore aggiunto delle proprietà, un argomento può essere fatto.


6

Sebbene i campi e le proprietà sembrino simili tra loro, sono 2 elementi del linguaggio completamente diversi.

  1. I campi sono l'unico meccanismo su come archiviare i dati a livello di classe. I campi sono concettualmente variabili nell'ambito della classe. Se si desidera archiviare alcuni dati nelle istanze delle classi (oggetti), è necessario utilizzare i campi. Non c'è altra scelta. Le proprietà non possono archiviare alcun dato, anche se potrebbe sembrare che siano in grado di farlo. Vedi sotto.

  2. Le proprietà invece non memorizzano mai i dati. Sono solo le coppie di metodi (get e set) che possono essere chiamati sintatticamente in modo simile ai campi e nella maggior parte dei casi accedono ai campi (per leggere o scrivere), che è fonte di confusione. Ma poiché i metodi di proprietà sono (con alcune limitazioni come il prototipo fisso) metodi C # regolari, possono fare qualunque cosa i metodi regolari possano fare. Significa che possono avere 1000 righe di codice, possono generare eccezioni, chiamare un altro metodo, possono anche essere virtuali, astratte o sovrascritte. Ciò che rende speciali le proprietà, è il fatto che il compilatore C # memorizza alcuni metadati extra in assiemi che possono essere utilizzati per cercare proprietà specifiche - funzionalità ampiamente utilizzate.

Ottenere e impostare i metodi di proprietà ha i seguenti prototipi.

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

Quindi significa che le proprietà possono essere "emulate" definendo un campo e 2 metodi corrispondenti.

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

Tale emulazione delle proprietà è tipica dei linguaggi di programmazione che non supportano le proprietà, come lo standard C ++. In C # dovresti sempre preferire le proprietà come modo di accedere ai tuoi campi.

Poiché solo i campi possono memorizzare dati, significa che contiene più campi della classe, verranno consumati più oggetti memoria di tale classe. D'altro canto, l'aggiunta di nuove proprietà in una classe non aumenta gli oggetti di tale classe. Ecco l'esempio.

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

Sebbene i metodi di proprietà possano fare qualsiasi cosa, nella maggior parte dei casi servono come un modo per accedere ai campi degli oggetti. Se vuoi rendere un campo accessibile ad altre classi, puoi farlo in 2 modi.

  1. Rendere i campi pubblici - non consigliabile.
  2. Utilizzando le proprietà.

Ecco una classe che utilizza campi pubblici.

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

Sebbene il codice sia perfettamente valido, dal punto di vista della progettazione, presenta diversi inconvenienti. Poiché i campi possono essere sia letti che scritti, non è possibile impedire all'utente di scrivere nei campi. Puoi applicare una readonlyparola chiave, ma in questo modo devi inizializzare i campi di sola lettura solo nel costruttore. Inoltre, nulla ti impedisce di memorizzare valori non validi nei tuoi campi.

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

Il codice è valido, tutti i compiti verranno eseguiti anche se sono illogici. Ageha un valore negativo, YearOfBirthè lontano in futuro e non corrisponde all'età ed FullNameè nullo. Con i campi non puoi impedire agli utenti di class Namecommettere tali errori.

Ecco un codice con proprietà che risolve questi problemi.

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

La versione aggiornata della classe presenta i seguenti vantaggi.

  1. FullNamee YearOfBirthvengono controllati valori non validi.
  2. Agenon è scrivibile. Viene chiamato YearOfBirthe dall'anno in corso.
  3. Una nuova proprietà viene FullNameInUppercaseconvertita FullNamein MAIUSCOLO. Questo è un piccolo esempio forzato dell'utilizzo delle proprietà, in cui le proprietà vengono comunemente utilizzate per presentare i valori dei campi nel formato più appropriato per l'utente, ad esempio utilizzando le impostazioni internazionali correnti su specifici numeri di DateTimeformato.

Oltre a ciò, le proprietà possono essere definite come virtuali o sovrascritte, semplicemente perché sono normali metodi .NET. Le stesse regole si applicano a tali metodi di proprietà come ai metodi regolari.

C # supporta anche gli indicizzatori che sono le proprietà che hanno un parametro index nei metodi di proprietà. Ecco l'esempio.

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

Poiché C # 3.0 consente di definire proprietà automatiche. Ecco l'esempio.

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

Anche se class AutoPropscontiene solo proprietà (o sembra), può memorizzare 2 valori e la dimensione degli oggetti di questa classe è uguale a sizeof(Value1)+sizeof(Value2)= 4 + 4 = 8 byte.

Il motivo è semplice. Quando si definisce una proprietà automatica, il compilatore C # genera un codice automatico che contiene un campo nascosto e una proprietà con metodi di proprietà che accedono a questo campo nascosto. Ecco il codice che il compilatore produce.

Ecco un codice generato da ILSpy dall'assembly compilato. La classe contiene campi e proprietà nascosti generati.

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

Quindi, come puoi vedere, il compilatore usa ancora i campi per memorizzare i valori, poiché i campi sono l'unico modo per archiviare i valori negli oggetti.

Come puoi vedere, sebbene proprietà e campi abbiano una sintassi di utilizzo simile sono concetti molto diversi. Anche se si utilizzano proprietà o eventi automatici, i campi nascosti vengono generati dal compilatore in cui sono memorizzati i dati reali.

Se devi rendere accessibile un valore di campo al mondo esterno (utenti della tua classe), non utilizzare campi pubblici o protetti. I campi devono sempre essere contrassegnati come privati. Le proprietà ti consentono di effettuare controlli di valore, formattazione, conversioni ecc. E generalmente rendono il tuo codice più sicuro, più leggibile e più estensibile per future modifiche.


4

Inoltre, le proprietà consentono di utilizzare la logica durante l'impostazione dei valori.

Quindi puoi dire che vuoi solo impostare un valore su un campo intero, se il valore è maggiore di x, altrimenti genera un'eccezione.

Funzionalità davvero utile.


4

Se hai intenzione di usare le primitive di thread sei costretto a usare i campi. Le proprietà possono violare il codice thread. A parte questo, ciò che Cory ha detto è corretto.


1
da quando? bloccare il campo supporto all'interno della proprietà ed è l'equivilant
Sekhat

1
Le proprietà sono metodi e non sono state sottolineate da CIL JIT oggi. Se hai intenzione di usare le primitive di thread come Interlocked devi avere dei campi. Controlla le tue fonti. Certamente "bloccare" era la parola sbagliata da usare.
Jonathan C Dickinson,

4

(Questo dovrebbe essere davvero un commento, ma non posso pubblicare un commento, quindi scusami se non è appropriato come post).

Una volta ho lavorato in un luogo in cui la pratica raccomandata era quella di utilizzare i campi pubblici anziché le proprietà quando la def equivalente della proprietà avrebbe appena avuto accesso a un campo, come in:

get { return _afield; }
set { _afield = value; }

Il loro ragionamento era che il campo pubblico poteva essere convertito in una proprietà in futuro, se necessario. Mi è sembrato un po 'strano in quel momento. A giudicare da questi post, sembra che non molti siano d'accordo. Cosa avresti potuto dire per provare a cambiare le cose?

Modifica: dovrei aggiungere che tutta la base di codice in questo posto è stata compilata contemporaneamente, quindi avrebbero potuto pensare che cambiare l'interfaccia pubblica delle classi (cambiando un campo pubblico in una proprietà) non fosse un problema.


A partire da C # 3.0 , il modello qui descritto è convenientemente supportato da una funzione chiamata Proprietà implementate automaticamente .
DavidRR

Penso che uno dei vantaggi in C # con Proprietà sia che hanno la stessa API dei campi, quindi ai clienti della classe non importa davvero se accedono a una proprietà o un campo. (Questo NON è vero in C ++ per esempio). Nella prototipazione, penso che sia ragionevole iniziare con campi pubblici e quindi migrare alle proprietà secondo necessità. Vi è un impatto sulle prestazioni e sulla memoria con proprietà e una digitazione aggiuntiva. Non sono liberi. Ma, se cambi idea, non dovrai refactificare alcun codice dipendente.
Mark Lakata,

Le proprietà non possono essere utilizzate come parametri OUT o REF, quindi la modifica di un campo in una proprietà potrebbe comportare errori di compilazione lungo la linea. Se il valore fosse stato implementato come proprietà dall'inizio, non sarebbe mai stato usato come parametro OUT o REF (VAR in Pascal / Delphi) e qualsiasi modifica apportata nel getter / setter sarebbe trasparente per l'uso.
HeartWare,

4

Tecnicamente, non penso che ci sia una differenza, perché le proprietà sono solo involucri attorno ai campi creati dall'utente o creati automaticamente dal compilatore. Lo scopo delle proprietà è quello di imporre l'incapsulamento e offrire una leggera funzionalità simile a un metodo. È solo una cattiva pratica dichiarare i campi pubblici, ma non ha alcun problema.


4

I campi sono variabili membro ordinarie o istanze membro di una classe. Le proprietà sono un'astrazione per ottenere e impostare i loro valori . Le proprietà sono anche chiamate accessori perché offrono un modo per modificare e recuperare un campo se si espone un campo nella classe come privato. In generale, è necessario dichiarare private le variabili del membro, quindi dichiarare o definire le proprietà per esse.

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }

3

Le proprietà incapsulano i campi, consentendo in tal modo di eseguire ulteriori elaborazioni sul valore da impostare o recuperare. In genere è eccessivo utilizzare le proprietà se non si esegue alcuna pre o post elaborazione sul valore del campo.


1
no, utilizzo sempre le proprietà, ti consente la flessibilità di modificare l'implementazione in qualsiasi momento senza interrompere l'API.
Sekhat,

Per quanto riguarda l'evoluzione dell'API, puoi utilizzare i campi per i dati privati senza problemi. Inoltre, nei casi dispari in cui si desidera condividere i dati all'interno di un assembly, è possibile fornire l'accesso "interno" ai campi.
Daniel Earwicker,

3

IMO, le proprietà sono solo le coppie di funzioni / metodi / interfacce "SetXXX ()" "GetXXX ()" che abbiamo usato prima, ma sono più concise ed eleganti.


3

I campi tradizionalmente privati ​​sono impostati tramite metodi getter e setter. Per motivi di minore quantità di codice, puoi invece utilizzare le proprietà per impostare i campi.


3

quando hai una classe che è "Car". Le proprietà sono colore, forma ..

Dove come campi sono variabili definite nell'ambito di una classe.


3

Da Wikipedia - Programmazione orientata agli oggetti :

La programmazione orientata agli oggetti (OOP) è un paradigma di programmazione basato sul concetto di "oggetti", che sono strutture di dati che contengono dati, sotto forma di campi , spesso noti come attributi; e codice, sotto forma di procedure, spesso conosciute come metodi . (enfasi aggiunta)

Le proprietà fanno effettivamente parte del comportamento di un oggetto, ma sono progettate per dare ai consumatori dell'oggetto l'illusione / l'astrazione di lavorare con i dati dell'oggetto.


3

La mia progettazione di un campo è che un campo deve essere modificato solo dal suo genitore, quindi dalla classe. Risultato la variabile diventa privata, quindi per essere in grado di dare il diritto di leggere le classi / i metodi all'esterno vado attraverso il sistema di proprietà con solo il Get. Il campo viene quindi recuperato dalla proprietà e di sola lettura! Se vuoi modificarlo devi passare attraverso i metodi (ad esempio il costruttore) e trovo che grazie a questo modo di renderti sicuro, abbiamo un migliore controllo sul nostro codice perché "flangiamo". Si potrebbe benissimo mettere sempre tutto in pubblico, quindi ogni possibile caso, la nozione di variabili / metodi / classi ecc ... secondo me è solo un aiuto per lo sviluppo, il mantenimento del codice. Ad esempio, se una persona riprende un codice con campi pubblici, può fare qualsiasi cosa e quindi cose "illogiche" in relazione all'obiettivo, la logica del perché il codice è stato scritto. È il mio punto di vista

Quando uso un campo privato di modello classico / proprietà di sola lettura pubbliche, per 10 campi privati ​​dovrei scrivere 10 proprietà di pubblico! Il codice può essere molto più grande e più veloce. Scopro il setter privato e ora uso solo proprietà pubbliche con un setter privato. Il setter crea in background un campo privato.

Ecco perché il mio vecchio stile di programmazione classico era:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

Il mio nuovo stile di programmazione:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}

Sì, mio ​​male, scusa!
Tony Pinot,

3

Pensaci: hai una stanza e una porta per entrare in questa stanza. Se vuoi controllare come entra e proteggere la tua stanza, allora dovresti usare le proprietà altrimenti non saranno nessuna porta e ognuno entrerà facilmente senza alcun regolamento

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

Le persone entrano nella sezione Uno abbastanza facilmente, non c'è stato alcun controllo

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

Ora hai controllato la persona e sai se ha qualcosa di malvagio con lui


3

I campi sono le variabili nelle classi. I campi sono i dati che è possibile incapsulare mediante l'uso di modificatori di accesso.

Le proprietà sono simili ai campi in quanto definiscono gli stati e i dati associati a un oggetto.

A differenza di un campo, una proprietà ha una sintassi speciale che controlla il modo in cui una persona legge i dati e li scrive, questi sono noti come operatori get e set. La logica impostata può spesso essere utilizzata per eseguire la convalida.


2

Le proprietà sono un tipo speciale di membro della classe, nelle proprietà utilizziamo un metodo Set o Get predefinito, che utilizza gli accessori attraverso i quali è possibile leggere, scrivere o modificare i valori dei campi privati.

Ad esempio, prendiamo una classe denominata Employee, con campi privati ​​per nome, età e Employee_Id. Non possiamo accedere a questi campi al di fuori della classe, ma possiamo accedere a questi campi privati ​​attraverso le proprietà.

Perché usiamo le proprietà?

Rendere pubblico il campo di classe ed esporlo è rischioso, poiché non avrai il controllo su ciò che viene assegnato e restituito.

Per capirlo chiaramente con un esempio, prendiamo una classe di studenti con ID, passmark, nome. Ora in questo esempio qualche problema con il campo pubblico

  • ID non dovrebbe essere -ve.
  • Il nome non può essere impostato su null
  • Il segno di passaggio deve essere di sola lettura.
  • Se manca il nome dello studente, nessun nome deve essere restituito.

Per rimuovere questo problema Usiamo il metodo Get and set.

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

Ora prendiamo un esempio del metodo get e set

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}

2

Informazioni aggiuntive: per impostazione predefinita, ottenere e impostare gli accessori sono accessibili quanto la proprietà stessa. È possibile controllare / limitare l'accessibilità degli accessi individualmente (per ottenere e impostare) applicando modificatori di accesso più restrittivi su di essi.

Esempio:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

Qui get è ancora accessibile pubblicamente (poiché la proprietà è pubblica), ma set è protetto (un identificatore di accesso più limitato).


2

Le proprietà vengono utilizzate per esporre il campo. Usano gli accessori (imposta, ottieni) attraverso i quali i valori dei campi privati ​​possono essere letti, scritti o manipolati.

Le proprietà non nominano le posizioni di archiviazione. Al contrario, dispongono di accessori che leggono, scrivono o calcolano i loro valori.

Usando le proprietà possiamo impostare la validazione sul tipo di dati che è impostato su un campo.

Ad esempio, abbiamo l'età del campo intero privato su cui dovremmo consentire valori positivi poiché l'età non può essere negativa.

Possiamo farlo in due modi usando getter e setter e usando la proprietà.

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

Proprietà implementata automaticamente se non otteniamo la logica in get e impostiamo gli accessori, possiamo usare la proprietà implementata automaticamente.

Quando si utilizzano compilazioni di proprietà implementate automaticamente, viene creato un campo privato e anonimo a cui è possibile accedere solo tramite get e set accessors.

public int Age{get;set;}

Proprietà astratte Una classe astratta può avere una proprietà astratta, che dovrebbe essere implementata nella classe derivata

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

Possiamo impostare privatamente una proprietà In questo possiamo impostare privatamente la proprietà automatica (impostata con nella classe)

public int MyProperty
{
    get; private set;
}

Puoi ottenere lo stesso con questo codice. In questo set di proprietà la funzione non è disponibile in quanto dobbiamo impostare direttamente il valore sul campo.

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

2

La stragrande maggioranza dei casi sarà un nome di proprietà a cui si accede anziché un nome di variabile ( campo ) La ragione di ciò è considerata buona pratica in .NET e in C # in particolare per proteggere ogni dato all'interno di una classe , sia che si tratti di una variabile di istanza o di una variabile statica (variabile di classe) perché è associata a una classe.

Proteggi tutte quelle variabili con le proprietà corrispondenti che ti consentono di definire, impostare e ottenere accessori e fare cose come la convalida quando stai manipolando quei pezzi di dati.

Ma in altri casi come la classe Math (spazio dei nomi di sistema), ci sono un paio di proprietà statiche integrate nella classe. uno dei quali è la costante matematica PI

per esempio. Math.PI

e poiché PI è un dato ben definito, non abbiamo bisogno di avere più copie di PI, sarà sempre lo stesso valore. Pertanto, a volte le variabili statiche vengono utilizzate per condividere i dati tra gli oggetti di una classe, ma vengono anche comunemente utilizzate per informazioni costanti in cui è necessaria solo una copia di un dato.

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.