Differenza tra proprietà e campo in C # 3.0+

Mi rendo conto che sembra essere un duplicato di Qual è la differenza tra un campo e una proprietà in C #? ma la mia domanda ha una leggera differenza (dal mio punto di vista):

Una volta lo so

  • Non userò la mia class con “tecniche che funzionano solo sulle proprietà” e
  • Non userò il codice di convalida nel getter / setter.

C’è qualche differenza (tranne lo stile / quelli futuri di sviluppo), come un qualche tipo di controllo nell’impostazione della proprietà?

C’è qualche differenza aggiuntiva tra:

public string MyString { get; set; } 

e

 public string myString; 

(Sono consapevole del fatto che la prima versione richiede C # 3.0 o superiore e che il compilatore crea i campi privati).

Incapsulamento.

Nella seconda istanza hai appena definito una variabile, nella prima c’è un getter / setter attorno alla variabile. Quindi se decidi di convalidare la variabile in un secondo momento, sarà molto più semplice.

Inoltre si presentano diversamente in Intellisense 🙂

Modifica: Aggiornamento per domande aggiornate OP: se si desidera ignorare gli altri suggerimenti qui, l’altro motivo è che non è semplicemente un buon design OO. E se non hai una buona ragione per farlo, scegli sempre una proprietà su una variabile pubblica / campo.

Campi e proprietà sembrano uguali, ma non lo sono. Le proprietà sono metodi e in quanto tali esistono alcune cose che non sono supportate per le proprietà e alcune cose che possono accadere con le proprietà ma mai nel caso dei campi.

Ecco un elenco di differenze:

  • I campi possono essere usati come input per out/ref argomenti out/ref . Le proprietà non possono.
  • Un campo produrrà sempre lo stesso risultato se chiamato più volte (se lasciamo fuori problemi con più thread). Una proprietà come DateTime.Now non è sempre uguale a se stessa.
  • Le proprietà possono generare eccezioni: i campi non lo faranno mai.
  • Le proprietà potrebbero avere effetti collaterali o richiedere molto tempo per l’esecuzione. I campi non hanno effetti collaterali e saranno sempre veloci come ci si può aspettare dal tipo specificato.
  • Le proprietà supportano l’accessibilità differente per getter / setter – i campi non lo fanno (ma i campi possono essere fatti in readonly )
  • Quando si utilizza la riflessione, le proprietà e i campi vengono trattati come diversi MemberTypes modo che si MemberTypes modo diverso (ad esempio GetFields e GetProperties )
  • Il compilatore JIT può trattare l’accesso alle proprietà in modo molto diverso rispetto all’accesso al campo. Può tuttavia essere compilato con codice nativo identico, ma lo scopo della differenza è lì.

Un paio di differenze veloci e ovvie

  1. Una proprietà può avere parole chiave accessorie.

     public string MyString { get; private set; } 
  2. Una proprietà può essere ignorata nei discendenti.

     public virtual string MyString { get; protected set; } 

La differenza fondamentale è che un campo è una posizione nella memoria in cui sono memorizzati i dati del tipo specificato. Una proprietà rappresenta una o due unità di codice che vengono eseguite per recuperare o impostare un valore del tipo specificato. L’uso di questi metodi di accesso è sintatticamente nascosto utilizzando un membro che sembra comportarsi come un campo (in quanto può apparire su entrambi i lati di un’operazione di assegnazione).

Gli accessori sono più che campi. Altri hanno già fatto notare alcune importanti differenze e ne aggiungerò un’altra.

Le proprietà partecipano alle classi di interfaccia. Per esempio:

 interface IPerson { string FirstName { get; set; } string LastName { get; set; } } 

Questa interfaccia può essere soddisfatta in diversi modi. Per esempio:

 class Person: IPerson { private string _name; public string FirstName { get { return _name ?? string.Empty; } set { if (value == null) throw new System.ArgumentNullException("value"); _name = value; } } ... } 

In questa implementazione stiamo proteggendo sia la class Person da entrare in uno stato non valido, sia il chiamante dall’ottenere nulla dalla proprietà non assegnata.

Ma potremmo spingere ulteriormente il design. Ad esempio, l’interfaccia potrebbe non occuparsi del setter. È del tutto legittimo affermare che i consumatori dell’interfaccia IPerson sono interessati solo a ottenere la proprietà, non a impostarla:

 interface IPerson { string FirstName { get; } string LastName { get; } } 

L’implementazione precedente della class Person soddisfa questa interfaccia. Il fatto che consenta al chiamante di impostare anche le proprietà è privo di significato dal punto di vista dei consumatori (che consumano IPerson ). Ulteriori funzionalità dell’implementazione concreta sono prese in considerazione, ad esempio, dal costruttore:

 class PersonBuilder: IPersonBuilder { IPerson BuildPerson(IContext context) { Person person = new Person(); person.FirstName = context.GetFirstName(); person.LastName = context.GetLastName(); return person; } } ... void Consumer(IPersonBuilder builder, IContext context) { IPerson person = builder.BuildPerson(context); Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } 

In questo codice, il consumatore non sa di chi si occupa della proprietà: non è suo compito conoscerlo. Il consumatore ha bisogno solo di getter e riceve i getter dall’interfaccia, cioè dal contratto.

Un’altra implementazione completamente valida di IPerson sarebbe una class persona immutabile e una fabbrica persona corrispondente:

 class Person: IPerson { public Person(string firstName, string lastName) { if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) throw new System.ArgumentException(); this.FirstName = firstName; this.LastName = lastName; } public string FirstName { get; private set; } public string LastName { get; private set; } } ... class PersonFactory: IPersonFactory { public IPerson CreatePerson(string firstName, string lastName) { return new Person(firstName, lastName); } } ... void Consumer(IPersonFactory factory) { IPerson person = factory.CreatePerson("John", "Doe"); Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } 

In questo codice, il consumatore campione ancora una volta non ha alcuna conoscenza del riempimento delle proprietà. Il consumatore tratta solo i getter e l’implementazione concreta (e la logica di business dietro di esso, come testare se il nome è vuoto) è lasciata alle classi specializzate – costruttori e fabbriche. Tutte queste operazioni sono assolutamente impossibili con i campi.

Il primo:

 public string MyString {get; set; } 

è una proprietà; il secondo ( public string MyString ) denota un campo.

La differenza è che certe tecniche (assegnamento dati ASP.NET per istanze) funzionano solo sulle proprietà e non sui campi. Lo stesso vale per la serializzazione XML: solo le proprietà sono serializzate, i campi non sono serializzati.

Proprietà e campi possono, in molti casi, sembrare simili, ma non lo sono. Esistono limitazioni alle proprietà che non esistono per i campi e viceversa.

Come altri hanno menzionato. È ansible rendere una proprietà di sola lettura o di sola scrittura rendendola accessoria privata. Non puoi farlo con un campo. Le proprietà possono anche essere virtuali, mentre i campi non possono.

Pensa alle proprietà come zucchero sintattico per le funzioni getXXX () / setXXX (). Questo è il modo in cui sono implementati dietro le quinte.

C’è un’altra importante differenza tra campi e proprietà.

Quando si utilizza WPF, è ansible associare solo proprietà pubbliche. Legarsi a un campo pubblico non funzionerà. Questo è vero anche quando non si implementa INotifyPropertyChanged (anche se si dovrebbe sempre).

Tra le altre risposte ed esempi, ritengo che questo esempio sia utile in alcune situazioni.

Ad esempio, supponiamo di avere una property OnChange come segue:

 public Action OnChange { get; set; } 

Se si desidera utilizzare i delegati di quello che è necessario modificare OnChange al field come questo:

 public event Action OnChange = delegate {}; 

In tale situazione proteggiamo il nostro campo da accessi indesiderati o modifiche.

È necessario utilizzare sempre le proprietà anziché i campi per tutti i campi pubblici. Ciò garantisce che la libreria abbia la capacità di implementare l’incapsulamento per qualsiasi campo se necessario in futuro senza rompere i codici esistenti. Se si sostituiscono i campi con le proprietà nelle librerie esistenti, tutti i anche i moduli dipendenti che usano la tua biblioteca devono essere ricostruiti.