2016-01-20 57 views
5

制定者I(據我)在C#結構和接口之間的差異怪沿來了。考慮這個接口和結構:C#的getter /在結構和接口

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

當我創建一個數字作爲屬性的新類,使用的changenumber方法來改變N到2並通過日誌打印的數量,它打印0而不是:

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

經過一段時間,我意識到這是因爲當我打電話給this.Number.ChangeNumber(2);時,我實際上創建了一個新對象(因爲getter)並將該數字更改爲2。但之後我更改了一些代碼物業編號爲:

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

在這種情況下,它打印2!這是爲什麼發生?結構的相同主體不適用於接口嗎?

+1

當它被引用爲接口時,它被裝箱。但總的來說,最好讓結構不可變,或者如果你需要可變性,你應該把它變成一個班級。 – juharr

回答

4

區別在於struct被用作值類型,其中interface(可以通過類或結構實現)是一個引用類型。

這使得在你的榜樣的巨大差異。在第一種情況下,對this.Number的調用意味着「讓我知道數字的值」 - 這意味着它會將值拉到堆棧上,並且堆棧中未存儲在任何地方的(未命名)變量會被修改。

在其他情況下,該接口是一個引用類型 - 這意味着,它得到無論是存儲在它的地址和修改它。

一般來說,我不會建議具有可變struct(如已經在評論中提到)。

你可以閱讀更多關於這個話題如Why are mutable structs 「evil」?

2

這是由NumberContainer類中的自動屬性引起的,您在訪問屬性時總是獲取值的副本。

如果更改屬性字段,它按預期工作。請記住,autoproperty只是一對方法,並且在返回/傳遞給/從任何方法時複製值類型。

當你調用

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

你actualy呼籲:

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

    this.getNumber() 
     .Log(); 

當您正在使用的界面,你正在返回的對象引用,所以操作總是相同的對象上執行。