2011-01-23 78 views
6

有人說我有一個屬性,它是一本字典<字符串,布爾>,使用對象初始化我可以用這句法(我覺得看起來很乾淨)一類:協變對象初始值設定項?

new MyClass() 
{ 
    Table = { {"test",true},{"test",false} } 
} 

然而,外我不能這樣做:

this.Table = { {"test",true},{"test",false} }; 

爲什麼初始值設定項是一個特殊情況?我猜測它與LINQ需求,協變或什麼都沒有關係,但它感覺有點不一致,無法在任何地方使用這種初始化器......

+0

有趣的問題。 – 2011-01-23 12:56:37

+0

我認爲編譯器錯誤是「預期表達式」的事實是一個很大的線索。在第二個例子中,語法並不像您通常所期望的那樣表示一個表達式,即沒有`new`操作符。我懷疑第一個例子是有效的,因爲它是一個特殊情況,編譯器對語法構成表達式的內容更加寬鬆。寬鬆規則的好處是對於對象初始化語法的上下文非常有用的特殊語法,否則它看起來會很難看。 – 2011-01-23 13:45:44

回答

0

考慮到你的語法在運行時拋出NullReferenceException - 你確定你可以使用它嗎?

public class Test 
{ 
    public Dictionary<string, bool> Table {get; set;} 
} 

public void TestMethod() 
{ 
    Test t = new Test { Table = { {"test", false} } }; //NullReferenceException 
} 

這編譯成以下的(經由反射器):

Test <>g__initLocal3 = new Test(); 
<>g__initLocal3.Table.Add("test", 0.0M); 

正如你可以看到,Table沒有初始化,從而產生NullReferenceException在運行時。

如果在Test的ctor中創建字典,類初始化程序會生成級聯Add語句,這是初始化程序中的語法糖(對於IEnumerable s)。

由於我們無法看到或想象的未知副作用,因此可能沒有引入正常代碼。 Eric Lippert可能會幫忙,因爲他可能對這件事情有更多的瞭解。

+2

是的,我知道,但不是完全相同的語法 – Homde 2011-01-23 12:57:43

+3

但是他不問他爲什麼你必須在它前面提供`新的Dictionary `。 – 2011-01-23 12:57:56

2

此限制遠比LINQ舊。即使回到C,你可以寫

int numbers[5] = {1, 2, 3, 4, 5}; 

但你不能用這個語法來給數組賦值。

我對C#背後的原因的猜測是,通常你不應該爲兩個不同的對象使用相同的引用。如果您需要將新集合分配給現有引用,則很可能您沒有很好地設計代碼,並且可以在定義時初始化集合,或者使用兩個單獨的引用而不是一個。

11

這個問題有點令人困惑,因爲問題與LINQ無關,與通用方差無關,並且具有集合初始值設定項以及對象初始值設定項。真正的問題是,據我可以告訴「爲什麼是不合法的使用集合初始化之外的對象創建表達式的?

相關的設計在這裏的原則是,在一般情況下,我們要操作的是創建和初始化對象,讓它們在某個地方具有「新」字樣,作爲向讀者發出信號的信號,即在此處發生對象創建。 (是的,這個規則在C#中有一些例外,作爲讀者的練習,看看你是否可以將它們命名爲全部。)

按照你的方式做事情會讓代碼難以理解。快,這是做什麼的?

d = new List<int>() { 10, 20, 30 }; 
d = { 40, 50, 60 }; 

是否第二線追加 40,50,60到現有列表?還是用新的名單取代舊名單?那裏沒有「新」,讀者有沒有期望新的對象被創建?

當你說

q = new Whatever() { MyList = { 40, 50, 60 } }; 

不創建一個新的列表;它將40,50,60添加到由構造函數分配的現有列表中。因此,你提出的語法是不明確的,並且對是否創建新列表感到困惑。

建議的功能既混亂又不必要,所以不可能很快實施。

相關問題