In C #, cosa rende un campo diverso da una proprietà e quando deve essere usato un campo invece di una proprietà?
In C #, cosa rende un campo diverso da una proprietà e quando deve essere usato un campo invece di una proprietà?
Risposte:
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.
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 string
a Surname
, allora la loro nuova classe Cognome comunica i vincoli e la proprietà public Surname LastName
non ha la validazione del setter. Inoltre, Surname
è riutilizzabile.
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.
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
}
public int myVar { get; set; }
rappresenta davvero (e presumo che sia la ragione per almeno il 50% dei risultati ottenuti da questa domanda).
virtual
è esso stesso parte della programmazione orientata agli oggetti.
virtual
OOP 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.
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.
Ti darò un paio di esempi sull'uso delle proprietà che potrebbero far girare gli ingranaggi:
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);
}
}
Dal momento che molti di loro hanno spiegato con pro e contro tecnici di Properties
e 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.Count
e dataTable.Columns[i].Caption
. Vengono dalla classe DataTable
ed entrambi sono pubblici per noi. La differenza nel loro livello di accesso è che non possiamo impostare il valore dataTable.Rows.Count
ma possiamo leggere e scrivere dataTable.Columns[i].Caption
. È possibile attraverso Field
? No!!! Questo può essere fatto Properties
solo 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 Button
Visual Studio. Le sue proprietà sono mostrate in modo PropertyGrid
simile Text
, Name
ecc. Quando trasciniamo un pulsante e quando facciamo clic sulle proprietà, troverà automaticamente la classe Button
e i filtri Properties
e la mostrerà in PropertyGrid
(dove PropertyGrid
non verranno mostrati 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
, le proprietà Name
e Text
verranno 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. Fields
non sono accettati da BindingSource
. Dovremmo usare Properties
per quello.
5. Modalità di debug
Considera che stiamo usando Field
per 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 Property
e 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;
}
}
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.
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.
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.
Sullo sfondo una proprietà viene compilata in metodi. Quindi una Name
proprietà 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.
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";
}
}
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 TransformPoint
diventa 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 volatile
parola 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.
Sebbene i campi e le proprietà sembrino simili tra loro, sono 2 elementi del linguaggio completamente diversi.
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.
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.
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 readonly
parola 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. Age
ha 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 Name
commettere 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.
FullName
e YearOfBirth
vengono controllati valori non validi.Age
non è scrivibile. Viene chiamato YearOfBirth
e dall'anno in corso.FullNameInUppercase
convertita FullName
in 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 DateTime
formato.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 AutoProps
contiene 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.
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.
(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.
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.
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;}
}
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.
IMO, le proprietà sono solo le coppie di funzioni / metodi / interfacce "SetXXX ()" "GetXXX ()" che abbiamo usato prima, ma sono più concise ed eleganti.
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.
quando hai una classe che è "Car". Le proprietà sono colore, forma ..
Dove come campi sono variabili definite nell'ambito di una classe.
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.
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;
}
}
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
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.
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
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;
}
}
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).
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; }
}
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.