2016-01-20 40 views
5

Sono arrivato con una strana differenza (secondo me) tra le strutture e le interfacce in C#. Considerate questa interfaccia e struct:C# getters/setters in structs e interfacce

public interface INumber 
{ 
    void ChangeNumber(int n); 
    void Log(); 
} 
public struct Number : INumber 
{ 
    private int n; 
    public void ChangeNumber(int n) 
    { 
     this.n = n; 
    } 
    public void Log() 
    { 
     Console.WriteLine(this.n); 
    } 
} 

Quando creo una nuova classe con un numero come proprietà, utilizzare il metodo ChangeNumber di cambiare n a 2 e stampare il numero utilizzando Log, stampa 0 invece:

public class NumberContainer 
{ 
    public Number Number { get; set; } 
    public NumberContainer() 
    { 
     this.Number = new Number(); 
     this.Number.ChangeNumber(2); 
     this.Number.Log();    //prints 0... 
    } 
} 

Dopo un po 'mi sono reso conto che era perché quando chiamo this.Number.ChangeNumber(2);, io in realtà creare un nuovo oggetto (a causa del getter) e cambiare il numero a 2. Ma poi ho cambiato un po' di codice cambiando il numero proprietà in una proprietà di INumber:

public class NumberContainer 
{ 
    public INumber Number { get; set; } 
    public NumberContainer() 
    { 
     this.Number = new Number(); 
     this.Number.ChangeNumber(2); 
     this.Number.Log();    //prints 2! 
    } 
} 

In questo caso, stampa 2! Perché sta succedendo? Lo stesso principio delle strutture non si applica all'interfaccia?

+1

Quando è referenziato come interfaccia, viene inserito in una scatola. Ma in generale è meglio rendere le strutture immutabili o se hai bisogno di mutevolezza dovresti renderlo una classe. – juharr

risposta

4

La differenza è che struct viene utilizzato come un tipo di valore, dove interface (che può essere implementato da una classe o una struttura) è un tipo di riferimento.

Questo fa una grande differenza nel tuo esempio. Quello che stai facendo nel primo caso la chiamata a this.Number significa "Ottieni il valore del numero" - il che significa che tira il valore sullo stack e la variabile (senza nome) sullo stack, che non è memorizzata da nessuna parte, viene modificata.

Nell'altro caso, l'interfaccia è un tipo di riferimento, il che significa che ottiene tutto ciò che è memorizzato nel suo indirizzo e lo modifica.

Generalmente non suggerirei di avere un mutabile struct (come già menzionato nei commenti).

Ulteriori informazioni su questo argomento, ad es. qui: Why are mutable structs “evil”?

2

Ciò è causato dalla proprietà auto nella classe NumberContainer, si ottiene sempre una copia del valore quando si accede alla proprietà.

Se si modifica la proprietà in un campo, funziona come previsto. Ricorda che l'autoproprietà è solo una coppia di metodi e che i tipi di valore vengono copiati quando vengono restituiti/passati a/da qualsiasi metodo.

Quando si sta chiamando

 this.Number.ChangeNumber(2); 
     this.Number.Log();    //prints 0... 

stai actualy chiamando:

this.getNumber() // returns copy of value type 
     .ChangeNumber(2); // executes op on that copy 

    this.getNumber() 
     .Log(); 

Quando si utilizza l'interfaccia si restituisce riferimento a un oggetto, in modo da operazioni vengono sempre eseguite sullo stesso oggetto.