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

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

Proprietà espone campi. I campi dovrebbero (quasi sempre) essere mantenuti privati ​​in una class 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 class.

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.

I principi di programmazione orientati agli oggetti dicono che i meccanismi interni di una class dovrebbero essere nascosti al mondo esterno. Se esponi un campo, in sostanza stai esponendo l’implementazione interna della class. Quindi avvolgiamo campi con Proprietà (o metodi nel caso di Java) per darci la possibilità di cambiare l’implementazione senza infrangere il codice a seconda di noi. Vedere come possiamo inserire la logica nella proprietà ci consente anche di eseguire la logica di convalida ecc. Se ne abbiamo bisogno. C # 3 ha la nozione, forse confusa, di autoproprietà. Questo ci permette 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 } 

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 class mentre i campi sono pensati per essere utilizzati nei meccanismi interni privati ​​di una class. Di regola raramente creo campi pubblici e, analogamente, raramente creo proprietà non pubbliche.

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 object che è costoso da caricare, ma non si accede a tutto ciò nelle normali esecuzioni del codice, è ansible 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’object.
  • Tracciamento sporco: che in realtà ho imparato dalla mia stessa domanda qui su StackOverflow. 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 object, il flag IsDirty non verrà triggersto, e quindi la funzionalità di salvataggio salterà su di esso al momento di decidere cosa è necessario tornare al database.

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 è ansible 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); } } } 

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 class 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 . È ansible 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 class 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 attributi . 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; } } 

DIFFERENZE – USI (quando e perché)

Un campo è una variabile dichiarata direttamente in una class o in una struttura. Una class 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 class espone al codice cliente dovrebbero essere forniti attraverso metodi, proprietà e indicizzatori. Utilizzando questi costrutti per l’accesso indiretto ai campi interni, è ansible 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 class 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.

Le proprietà hanno il vantaggio principale di consentire di modificare il modo in cui si accede ai dati su un object senza rompere la sua interfaccia pubblica. Ad esempio, se è necessario aggiungere una convalida aggiuntiva o modificare un campo memorizzato in un calcolo, è ansible farlo facilmente se inizialmente esposto il campo come proprietà. Se hai appena esposto un campo direttamente, dovresti modificare l’interfaccia pubblica della tua class 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 class 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.

Sullo sfondo una proprietà è compilata in metodi. Quindi una proprietà Name è compilata in get_Name() e set_Name(string value) . Puoi vedere questo se studi il codice compilato. Quindi c’è un sovraccarico di prestazioni (molto) piccolo quando li si usa. Normalmente si utilizzerà sempre una proprietà se si espone un campo all’esterno e lo si utilizzerà spesso internamente se è necessario eseguire la convalida del valore.

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.

Quando vuoi che la tua variabile privata (campo) sia accessibile all’object della tua class da altre classi devi creare proprietà per tali variabili.

per esempio se ho variabili chiamate “id” e “name” che sono private ma potrebbe esserci una situazione in cui questa variabile è necessaria per operazioni di lettura / scrittura al di fuori della class. In questa situazione, la proprietà può aiutarmi a ottenere quella variabile in lettura / scrittura a seconda del risultato / set definito per la proprietà. Una proprietà può essere sia readonly / writeonly / readwrite.

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

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

In generale, tutte le altre risposte sono chiare sul buon design: preferiscono esporre le proprietà oltre i campi di esposizione. Mentre probabilmente non ti troverai regolarmente a dire “wow, immagina quante cose peggiori sarebbero se avessi fatto di questo un campo invece di una proprietà”, è molto più raro pensare a una situazione in cui potresti dire “wow, grazie a Dio ho usato un campo qui invece di una proprietà “.

Ma c’è un vantaggio che i campi hanno sulle proprietà, e questa è 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, penso che il modo più veloce per farlo, poiché 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 misurazioni che dimostrano il contrario, non c'è motivo di gettare una puzza. Ma credo che non sia tecnicamente garantito essere così 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 i campi richiede circa il 61% del tempo come versione con proprietà (.NET 4.6, Windows 7, x64, modalità di rilascio, nessun debugger collegato). Quanto più costoso diventa il metodo TransformPoint , tanto meno pronunciato diventa la differenza. Per ripetere tu stesso, corri con la prima riga commentata e con essa non commentata.

Anche se non ci sono benefici per le prestazioni di cui sopra, ci sono altri luoghi in cui la possibilità di utilizzare i parametri ref e out potrebbe essere utile, come quando si chiama la famiglia di metodi Interlocked o Volatile . Nota: nel caso in cui questo sia nuovo per te, Volatile è fondamentalmente un modo per ottenere lo stesso comportamento fornito dalla parola chiave volatile . Come tale, come volatile , non risolve magicamente tutti i problemi legati alla sicurezza del thread, come suggerisce il nome stesso.

Sicuramente non voglio sembrare come se stessi sostenendo che tu vai "oh, dovrei iniziare a esporre campi invece di proprietà". Il punto è che se hai bisogno di usare regolarmente questi membri in chiamate che prendono parametri "ref" o "out", specialmente su qualcosa che potrebbe essere un semplice tipo di valore che è improbabile che abbia mai bisogno di uno qualsiasi degli elementi a valore aggiunto delle proprietà, un argomento può essere fatto.

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

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

(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.

Questa pagina su MSDN ha un confronto e suggerimenti su quale utilizzare quando:

https://msdn.microsoft.com/en-us/library/9d65as2e(v=vs.90).aspx

I campi sono variabili membro ordinarie o istanze membro di una class. 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 class 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;} } 

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.

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 ctriggers pratica dichiarare i campi come pubblici, ma non ha alcun problema.

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

Tradizionalmente i campi privati ​​sono impostati tramite metodi getter e setter. Per motivi di meno codice è ansible utilizzare le proprietà per impostare i campi.

quando hai una class che è “Car”. Le proprietà sono colore, forma ..

Dove i campi sono variabili definite nell’ambito di una class.

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à sono in realtà parte del comportamento di un object, ma sono progettate per fornire ai consumatori dell’object l’illusione / astrazione del lavoro con i dati dell’object.

Le proprietà sono un tipo speciale di membro della class. Nelle proprietà utilizziamo un metodo Set o Get predefinito. Utilizzano gli accessor tramite i quali possiamo leggere, scrivere o modificare i valori dei campi privati.

Ad esempio, prendiamo una class di nome Employee , con campi privati ​​per nome, età e Employee_Id. Non possiamo accedere a questi campi dall’esterno della class, ma possiamo accedere a questi campi privati ​​attraverso le proprietà.

Perché usiamo le proprietà?

Rendere pubblico il campo class ed esporlo è rischioso, in quanto non si avrà il controllo di ciò che viene assegnato e restituito.

Per comprenderlo chiaramente con un esempio, prendi una class studentesca che ha ID, passmark, nome. Ora in questo esempio qualche problema con il campo pubblico

  • L’ID non dovrebbe essere -ve.
  • Il nome non può essere impostato su null
  • Il contrassegno deve essere letto solo
  • Se manca il nome dello studente, nessun nome deve essere restituito.

Per rimuovere questo problema Usiamo il metodo Get e 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 di 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; } } 

Il mio progetto di un campo è che un campo deve essere modificato solo dal suo genitore, quindi dalla class. 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! If you want to modify it you have to go through methods (for example the constructor) and I find that thanks to this way of making you secure, we have better control over our code because we “flange”. One could very well always put everything in public so every possible case, the notion of variables / methods / classs etc … in my opinion is just an aid to the development, maintenance of the code. For example, if a person resumes a code with public fields, he can do anything and therefore things “illogical” in relation to the objective, the logic of why the code was written. It’s my point of view.

When i use a classic model private field / public readonly properties,for 10 privates fields i should write 10 publics properties! The code can be really big faster. I discover the private setter and now i only use public properties with a private setter. The setter create in background a private field.

That why my old classic programming style was:

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

My new programming style:

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

The vast majority of cases it’s going to be a property name that you access as opposed to a variable name ( field ) The reason for that is it’s considered good practice in .NET and in C# in particular to protect every piece of data within a class, whether it’s an instance variable or a static variable (class variable) because it’s associated with a class.

Protect all of those variables with corresponding properties which allow you to define, set and get accessors and do things like validation when you’re manipulating those pieces of data.

But in other cases like Math class (System namespace), there are a couple of static properties that are built into the class. one of which is the math constant PI

per esempio. Math.PI

and because PI is a piece of data that is well-defined, we don’t need to have multiple copies of PI, it always going to be the same value. So static variables are sometimes used to share data amongst object of a class, but the are also commonly used for constant information where you only need one copy of a piece of data.

Additional info: By default, get and set accessors are as accessible as the property itself. You can control/restrict accessor accessibility individually (for get and set) by applying more restrictive access modifiers on them.

Esempio:

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

Here get is still publicly accessed (as the property is public), but set is protected (a more restricted access specifier).

Properties are used to expose field. They use accessors(set, get) through which the values of the private fields can be read, written or manipulated.

Properties do not name the storage locations. Instead, they have accessors that read, write, or compute their values.

Using properties we can set validation on the type of data that is set on a field.

For example we have private integer field age on that we should allow positive values since age cannot be negative.

We can do this in two ways using getter and setters and using property.

  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() } } 

Auto Implemented property if we don't logic in get and set accessors we can use auto implemented property.

When u se auto-implemented property compiles creates a private, anonymous field that can only be accessed through get and set accessors.

 public int Age{get;set;} 

Abstract Properties An abstract class may have an abstract property, which should be implemented in the derived class

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

We can privately set a property In this we can privately set the auto property(set with in the class)

 public int MyProperty { get; private set; } 

You can achieve same with this code. In this property set feature is not available as we have to set value to field directly.

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

Think about it : You have a room and a door to enter this room. If you want to check how who is coming in and secure your room, then you should use properties otherwise they won’t be any door and every one easily come in w/o any regulation

 class Room { public string sectionOne; public string sectionTwo; } Room r = new Room(); r.sectionOne = "enter"; 

People is getting in to sectionOne pretty easily, there wasn’t any checking

 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"; 

Now you checked the person and know about whether he has something evil with him