Differenza tra proprietà e campo in C # 3.0+


140

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 che lo so

  • Non userò la mia classe con "tecniche che funzionano solo su proprietà" e
  • Non userò il codice di validazione nel getter / setter.

C'è qualche differenza (eccetto quelli di stile / sviluppo futuro), 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 che la prima versione richiede C # 3.0 o versioni successive e che il compilatore crea i campi privati.)


Risposte:


117

Incapsulamento.

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

Inoltre si presentano in modo diverso in Intellisense :)

Modifica: domanda di aggiornamento per OP aggiornata - se si desidera ignorare gli altri suggerimenti qui, l'altro motivo è che semplicemente non è un buon design OO. E se non hai un'ottima ragione per farlo, scegli sempre una proprietà su una variabile / un campo pubblici.


9
Perché sarà più facile? Cosa mi impedisce di trasformare un campo in una proprietà e aggiungere un campo di supporto privato? In che modo ciò influisce sul codice chiamante?
Serge Wautier,

30
@Serge: influisce sul codice già compilato. Ad esempio, se si sta sviluppando una libreria utilizzata da diverse applicazioni, la modifica di un campo in una proprietà in quella libreria richiederebbe una ricompilazione di ciascuna applicazione. Se fosse una proprietà, è possibile aggiornare la proprietà senza preoccupazioni.
Dustin Campbell,

Sono totalmente d'accordo con te, utilizzo sempre le proprietà. Ero solo curioso di una possibile differenza
p4bl0,

24
Se il consumo del codice viene sempre ricompilato contemporaneamente alla classe interessata (quindi qualsiasi cosa privata o interna senza interni visibili è sicura al 100%), renderlo un campo è perfettamente OK
ShuggyCoUk

1
wow Shuggy il tuo commento è esattamente la risposta che stavo cercando!
p4bl0,

160

I campi e le proprietà sembrano uguali, ma non lo sono. Le proprietà sono metodi e come tali ci sono 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 utilizzati come input per gli out/refargomenti. Le proprietà non possono.
  • Un campo produrrà sempre lo stesso risultato quando viene chiamato più volte (se tralasciamo problemi con più thread). Una proprietà come DateTime.Nownon è sempre uguale a se stessa.
  • Le proprietà possono generare eccezioni: i campi non lo faranno mai.
  • Le proprietà possono avere effetti collaterali o richiedere molto tempo per essere eseguite. I campi non hanno effetti collaterali e saranno sempre più veloci di quanto ci si possa aspettare per un determinato tipo.
  • Le proprietà supportano accessibilità diversa per getter / setter - i campi no (ma i campi possono essere creati readonly)
  • Quando si utilizza la riflessione, le proprietà e i campi vengono trattati in MemberTypesmodo diverso in modo da trovarsi in modo diverso ( GetFieldsrispetto GetPropertiesad esempio)
  • Il compilatore JIT può trattare l'accesso alla proprietà in modo molto diverso rispetto all'accesso sul campo. Tuttavia, può essere compilato in un codice nativo identico, ma esiste l'ambito della differenza.

11
Si noti tuttavia che molti di questi punti non dovrebbero essere differenze se si utilizzano le buone pratiche. Cioè, le proprietà non dovrebbero mai avere effetti collaterali, né dovrebbero richiedere molto tempo per essere eseguite.
Noldorin,

15
@Noldorin: sono d'accordo, ma sfortunatamente dovrebbe essere la parola chiave qui. Con i campi tale comportamento è garantito. Non sto dicendo che dovresti usare i campi, ma è importante essere consapevoli delle differenze semantiche.
Brian Rasmussen,

4
Sì, abbastanza giusto. I programmatori principianti non hanno la minima idea di queste cose, sfortunatamente ...
Noldorin

2
Inoltre, i campi possono avere un inizializzatore di campo mentre le proprietà devono essere inizializzate in un costruttore.
Dio F,

3
Sento che questa risposta è di gran lunga migliore della risposta accettata. Sto iniziando a pensare che il modo "accettabile" di preferire sempre le proprietà ai campi sia una cattiva idea. Se hai solo bisogno di gestire i dati, usa un campo. Se è necessario applicare funzionalità ai dati, utilizzare un metodo. Poiché le proprietà possono avere effetti collaterali di cui non sei a conoscenza (soprattutto se non hai progettato la libreria e hai poca documentazione), nella maggior parte dei casi mi sembrano contro intuitivi.
David Peterson,

41

Un paio di differenze ovvie e veloci

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

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

    public virtual string MyString { get; protected set; }

1
mmh .. nr 2 è interessante .. non ci avevo pensato
p4bl0

14

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 usando un membro che sembra comportarsi come un campo (in quanto può apparire su entrambi i lati di un'operazione di assegnazione).


11

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

Le proprietà prendono parte 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 Personclasse da entrare in uno stato non valido, sia il chiamante da ottenere null dalla proprietà non assegnata.

Ma potremmo spingere ulteriormente il design. Ad esempio, l'interfaccia potrebbe non gestire il setter. È abbastanza legittimo affermare che i consumatori di IPersoninterfaccia sono interessati solo a ottenere la proprietà, non a impostarla:

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

La precedente implementazione della Personclasse soddisfa questa interfaccia. Il fatto che consenta al chiamante di impostare anche le proprietà non ha senso 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 è a conoscenza dei setter di proprietà, non è compito suo conoscerlo. Il consumatore ha solo bisogno di vincitori e ottiene vincitori dall'interfaccia, cioè dal contratto.

Un'altra implementazione completamente valida di IPersonsarebbe una classe di persona immutabile e una fabbrica di 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 di esempio non ha ancora una conoscenza del riempimento delle proprietà. Il consumatore si occupa solo di getter e l'implementazione concreta (e la logica aziendale dietro di essa, come test se il nome è vuoto) è lasciato alle classi specializzate - costruttori e fabbriche. Tutte queste operazioni sono assolutamente impossibili con i campi.


7

Il primo:

public string MyString {get; set; }

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

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


8
Sbagliato. La serializzazione XML serializza i campi pubblici.
Serge Wautier,

2
Può essere. Ma quando si crea un'origine dati oggetto da una classe, si utilizzano solo le proprietà, non i campi. (A meno che non abbia fatto qualcosa di sbagliato: P)
Svish

Buono a SECCO;) ma scrivo ancora una volta, mi piace il ruolo forte della proprietà nel linguaggio C #. È molto meglio implementato rispetto a Java (di conseguenza dall'inizio) Molte, forse tutte le soluzioni .net funzionano solo su proprietà. WPF, ASPX e altro.
Jacek CZ

3

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 già detto. È possibile creare una proprietà di sola lettura o di sola scrittura rendendola accessor privata. Non puoi farlo con un campo. Le proprietà possono anche essere virtuali, mentre i campi no.

Pensa alle proprietà come zucchero sintattico per le funzioni getXXX () / setXXX (). Ecco come sono implementati dietro le quinte.


1

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

Quando si utilizza WPF, è possibile associare solo a proprietà pubbliche. Il collegamento a un campo pubblico non funzionerà. Questo è vero anche se non implementato INotifyPropertyChanged(anche se dovresti sempre).


Buono a SECCO;) ma scrivo ancora una volta, mi piace il ruolo forte della proprietà nel linguaggio C #. È molto meglio implementato rispetto a Java (di conseguenza dall'inizio) Molte, forse tutte le soluzioni .net funzionano solo su proprietà. WPF, ASPX e altro.
Jacek CZ

1

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

Ad esempio, supponiamo che tu abbia un simile seguito:OnChange property

public Action OnChange { get; set; }

Se si desidera utilizzare i delegati di quanto sia necessario modificarlo OnChangein fieldquesto modo:

public event Action OnChange = delegate {};

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


0

Dovresti sempre usare le proprietà anziché i campi per tutti i campi pubblici. Ciò garantisce che la tua biblioteca abbia la possibilità di implementare l'incapsulamento per qualsiasi campo se necessario in futuro senza rompere i codici esistenti. Se sostituisci i campi con proprietà nelle librerie esistenti, allora tutti i anche i moduli dipendenti che utilizzano la libreria devono essere ricostruiti.


"sempre" è un privilegio di parola difficile. In C # (meglio che in Java) la proprietà ha una posizione forte, è (probabilmente senza eccezioni) principale / metodo di "associazione" in ASP, WPF e altri. Ciononostante, posso immaginare che il design con un campo senza essere proprietà abbia senso (a volte)
Jacek Cz
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.