c# - property - Qual è la differenza tra un campo e una proprietà?




proprietà c# (20)

In C #, cosa rende un campo diverso da una proprietà e quando dovrebbe essere usato un campo al posto di una proprietà?


DIFFERENZE - USI (quando e perché)

Un campo è una variabile dichiarata direttamente in una classe o in una struttura. Una classe o una struttura possono avere campi di istanza o campi statici o entrambi. In genere, è necessario utilizzare i campi solo per le variabili che dispongono di accessibilità privata o protetta . I dati che la tua classe espone al codice cliente dovrebbero essere forniti attraverso 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 accessor . Ciò consente di accedere facilmente ai dati e contribuisce a promuovere la sicurezza e la flessibilità dei metodi . Le proprietà consentono a una classe di esporre un metodo pubblico per ottenere e impostare valori, nascondendo il codice di implementazione o di verifica. Una proprietà di accesso get viene utilizzata per restituire il valore della proprietà e un accessor set viene utilizzato per assegnare un nuovo valore.


(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 lo studio consigliato consisteva nell'utilizzare i campi pubblici anziché le proprietà quando la def equivalente della proprietà avrebbe appena dovuto accedere 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à più tardi in futuro, se necessario. Mi è sembrato un po 'strano in quel momento. A giudicare da questi post, sembra che non molti qui sarebbero d'accordo. Cosa potevi dire per cercare di cambiare le cose?

Edit: Devo aggiungere che tutto il codice base in questo posto è stato compilato allo stesso tempo, quindi avrebbero potuto pensare che cambiare l'interfaccia pubblica delle classi (cambiando un campo pubblico in una proprietà) non fosse un problema.


Dal momento che molti di loro hanno spiegato con pro e contro tecnici di Properties e Field , è il momento 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.Count e dataTable.Columns[i].Caption . Vengono dalla classe DataTable ed entrambi sono pubblici per noi. La differenza nel livello di accesso a loro è che non possiamo impostare valore su dataTable.Rows.Count ma possiamo leggere e scrivere su dataTable.Columns[i].Caption . È possibile attraverso il Field ? No!!! Questo può essere fatto solo con Properties .

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 Button in Visual Studio. Le sue proprietà sono mostrate in PropertyGrid come Text , Name ecc. Quando trasciniamo un pulsante e quando clicchiamo sulle proprietà, troverà automaticamente la classe Button e filtri Properties e mostreremo che in PropertyGrid (dove PropertyGrid non mostrerà Field anche 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 , verranno mostrate le proprietà Name e Text , ma non SomeProperty . Perché??? Perché le proprietà possono accettare Attributes . Non viene visualizzato nel caso in cui [Browsable(false)] sia false.

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 in Binding Source

Binding Source ci aiuta a ridurre il numero di righe di codice. Fields non sono accettati da BindingSource . Dovremmo usare le Properties per quello.

5. Modalità di debug

Considera che stiamo usando Field per mantenere un valore. A un certo punto dobbiamo eseguire il debug e verificare dove il valore sta diventando nullo per quel campo. Sarà difficile da fare dove il numero di righe di codice è più di 1000. In tali situazioni possiamo usare Property e possiamo impostare la modalità di debug all'interno di Property .

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

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 denominate accessors perché offrono un modo per cambiare e recuperare un campo se si espone un campo nella classe come privato. In generale, è necessario dichiarare le proprie variabili membro private, quindi dichiarare o definire proprietà per esse.

  class SomeClass
  {
     int numbera; //Field

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

  }

IMO, Proprietà sono solo le coppie di funzioni / metodi / interfacce "SetXXX ()" "GetXXX ()" utilizzate in precedenza, ma sono più concise ed eleganti.


Inoltre, le proprietà consentono di utilizzare la logica quando si impostano i valori.

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

Caratteristica davvero utile


Le proprietà hanno il vantaggio principale di consentire di modificare il modo in cui si accede ai dati su un oggetto senza rompere la sua interfaccia pubblica. Ad esempio, se è necessario aggiungere una convalida aggiuntiva o modificare un campo memorizzato in un calcolo, è possibile farlo facilmente se inizialmente esposto il campo come proprietà. Se hai appena esposto un campo direttamente, dovresti modificare l'interfaccia pubblica della tua classe per aggiungere la nuova funzionalità. Quel cambiamento potrebbe rompere i client esistenti, richiedendo loro di essere ricompilati prima che potessero usare la nuova versione del tuo codice.

Se si scrive una libreria di classi progettata per un consumo ampio (come .NET Framework, che viene utilizzato da milioni di persone), ciò può rappresentare un problema. Tuttavia, se stai scrivendo una classe usata internamente in una piccola base di codice (diciamo <= 50 linee K), non è davvero un grosso problema, perché nessuno potrebbe essere influenzato negativamente dalle tue modifiche. In tal caso, si tratta solo di preferenze personali.


Le proprietà incapsulano i campi, consentendo così di eseguire un'ulteriore elaborazione sul valore da impostare o recuperare. Generalmente è eccessivo usare le proprietà se non si sta facendo alcun pre o post-elaborazione sul valore del campo.


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 puoi sempre 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 funzionare per un tempo molto lungo, avere effetti collaterali e possono anche generare eccezioni. I campi sono veloci, senza effetti collaterali e non generano mai eccezioni. A causa di effetti collaterali, una proprietà può restituire un valore diverso per ogni chiamata (come potrebbe essere il caso per DateTime.Ora, ad esempio DateTime.Ora non è sempre uguale a DateTime.Now). I campi restituiscono sempre lo stesso valore.

I campi possono essere usati per i parametri out / ref, le proprietà no. Le proprietà supportano la logica aggiuntiva, che potrebbe essere utilizzata per implementare il caricamento lazy tra le altre cose.

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

Utilizzare le proprietà nella maggior parte / tutti i casi, ma cercare di evitare effetti collaterali.


Proprietà espone campi. I campi dovrebbero (quasi sempre) essere mantenuti privati ​​in una classe e accessibili tramite le proprietà get e set. Le proprietà forniscono un livello di astrazione che consente di modificare i campi senza influire sul modo esterno a cui accedono le 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 richieste per incapsulare i campi, potrebbero eseguire un calcolo su altri campi o servire ad altri scopi.

@GSS sottolinea che puoi anche fare altra logica, come la convalida, quando si accede a una proprietà, un'altra caratteristica utile.



Se si intende utilizzare le primitive del thread, si è obbligati a utilizzare i campi. Le proprietà possono rompere il codice filettato. A parte ciò, ciò che ha detto è corretto.


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


Ti darò un paio di esempi di utilizzo di proprietà che potrebbero far girare gli ingranaggi:

  • Inizializzazione pigra : se si dispone di una proprietà di un oggetto che è costoso da caricare, ma non si accede a tutto ciò nelle normali esecuzioni del codice, è possibile ritardarne il caricamento tramite la proprietà. In questo modo, è solo 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ò velocizzare notevolmente l'inizializzazione dell'oggetto.
  • Tracciamento sporco: che in realtà ho imparato dalla mia stessa domanda qui su . Quando ho molti oggetti che i valori potrebbero essere cambiati durante una corsa, posso usare la proprietà per tenere traccia 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 quindi la funzionalità di salvataggio salterà su di esso al momento di decidere cosa è necessario tornare al database.

Una differenza importante è che le interfacce possono avere proprietà ma non campi. Questo, per me, sottolinea che le proprietà dovrebbero essere utilizzate per definire l'interfaccia pubblica di una classe mentre i campi sono pensati per essere utilizzati nei meccanismi interni privati ​​di una classe. Di regola raramente creo campi pubblici e, analogamente, raramente creo proprietà non pubbliche.


Usando Properties, puoi lanciare un evento, quando il valore della proprietà viene modificato (aka. PropertyChangedEvent) o prima che il valore venga modificato per supportare l'annullamento.

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(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}

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

Le proprietà sono simili ai campi in quanto definiscono stati e 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 scrive i dati, questi sono noti come operatori get e set. La logica dell'insieme può essere spesso utilizzata per convalidare.


Il mio progetto 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 / metodi all'esterno passo il sistema di proprietà con solo 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 controllo migliore sul nostro codice perché "flangia". Si potrebbe benissimo mettere sempre tutto in pubblico così ogni possibile caso, la nozione di variabili / metodi / classi ecc ... secondo me è solo un aiuto allo sviluppo, alla manutenzione del codice. Ad esempio, se una persona riprende un codice con campi pubblici, può fare qualsiasi cosa e quindi le cose "illogiche"in relazione all'obiettivo, la logica del perché il codice è stato scritto. È il mio punto di vista.

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

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

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

Proteggi tutte queste variabili con proprietà corrispondenti che ti permettono di definire, impostare e ottenere accessors e fare cose come la validazione quando stai manipolando quei pezzi di dati.

Ma in altri casi come la classe Math (System namespace), ci sono un paio di proprietà statiche che sono incorporate nella classe. uno dei quali è la costante matematica PI

per esempio. Math.PI

e poiché PI è un pezzo di dati ben definito, non è necessario disporre di più copie di PI, sarà sempre lo stesso valore. Quindi le variabili statiche sono talvolta utilizzate per condividere i dati tra gli oggetti di una classe, ma sono anche comunemente usati per informazioni costanti in cui è necessaria solo una copia di un pezzo di dati.


Le proprietà sono usate per esporre il campo. Usano gli accessor (set, get) attraverso i quali i valori dei campi privati ​​possono essere letti, scritti o manipolati.

Le proprietà non nominano le posizioni di memoria. Invece, hanno accessor 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 un'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 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à Auto Implementata se non eseguiamo la logica in get e set accessors possiamo usare la proprietà auto implementata.

Quando la compilazione di proprietà auto-implementata crea un campo privato, 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à auto (impostata con nella classe)

public int MyProperty
{
    get; private set;
}

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

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




field