2010-10-27 122 views
52

給出下面的代碼,position0的初始化方式和position1的初始化方式有什麼區別?它們是否相同?如果不是,有什麼區別?C#新語句後的大括號是什麼?

class Program 
{ 
    static void Main(string[] args) 
    { 
     Position position0 = new Position() { x=3, y=4 }; 

     Position position1 = new Position(); 
     position1.x = 3; 
     position1.y = 4; 
    } 
} 

struct Position 
{ 
    public int x, y; 
} 

回答

41

對象和集合初始化器,用於初始化對象上的字段。

http://msdn.microsoft.com/en-us/library/bb384062.aspx

他們生產幾乎相當於 IL。 Jon Skeet對真正發生的事情有了答案。

+1

很多事實。張貼我的答案...看到他的答案,編輯它指出他的答案。 – 2010-10-27 16:45:32

+0

喬恩Skeet似乎回答在這個網站上的每個問題:)我迫不及待地閱讀他的新書(如果它實際上得到釋放) – Bryan 2010-10-27 16:55:01

1

這些完全等同。編譯器實際上只是將第一個版本轉換爲第二個版本。

兩者之間的唯一區別是,第一,你可以做很好的變薄,如通過初始化版本的方法:

DoSomethingWithPoint(new Position() { x=3, y=4 }); 

這是一個代碼很多線路比第二初始化例。

2

您的兩個代碼示例將生成相同的IL。 (至少在發佈版本中)

5

這是一個對象初始化程序,只是允許您在單個表達式中分配值。最重要的是,這也適用於LINQ an中的匿名類型(否則不可變)。 addi項目也有類似的集合初始化語法到新的集合。

請注意,有一個微妙的時間問題是有用的;與初始化的分配/添加全部發生之前該變量被分配,這可以幫助阻止其他線程看到一個不完整的對象。否則,您需要額外的變量才能達到相同的結果。

+0

約書亞和斯拉克斯公佈,初始化'位置'的兩種方式產生等效的IL。你是說用匿名類型,我會得到不同的結果? – 2010-10-27 15:12:46

+0

@rice - 是的:只有其中一個會編譯:) – 2010-10-27 15:14:27

1

它們是等價的,除了一個比另一個更容易閱讀。

還要考慮的情況下,當你想通過新的對象一起到別的地方:

var aList = new List<Position>(); 
aList.Add(new Position() { x=3, y=4 }); 
51

他們不是相當等同 - 至少不是在一般情況下。使用對象初始化的代碼更接近這樣的:

Position tmp = new Position(); 
tmp.x = 3; 
tmp.y = 4; 
Position position1 = tmp; 

換句話說,分配給變量只發生後的屬性已被設置。現在,如果你聲明瞭一個新的局部變量,那實際上並不重要,編譯器可能會優化你的第一個表單。但從邏輯上講,這很重要。試想一下:

Position p1 = new Position { x = 10, y = 20 }; 

p1 = new Position { x = p1.y, y = p1.x }; 

如果沒有分配給p1第一,你最終以0兩個p1.xp1.y。而這實際上相當於:

Position tmp = new Position(); 
tmp.x = 10; 
tmp.y = 20; 
Position p1 = tmp; 

tmp = new Position(); 
tmp.x = p1.y; // 20 
tmp.y = p1.x; // 10 
p1 = tmp; 

編輯:我剛剛意識到你正在使用一個結構,而不是一個類。這可能會產生一些細微的差異......但你幾乎肯定不應該使用可變結構來開始:)

2

忘記所有IL的東西,它只是簡寫符號。你在做什麼是這樣的:

a。在一種情況下,您明確使用默認的構造函數,然後設置兩個屬性。

b。另一方面,您正在使用新的初始化語法,它隱式地使編譯器執行您在大小寫a中執行的操作。

IL subtelties儘管他們會爲你實現同樣的事情。