2009-09-16 45 views
1

這是一個後續的問題,另外一個問題我在這裏問: Calling constructor from other constructor in same class at the endC#禁止調用默認構造函數的根本原因是什麼?

前一個是關於怎麼樣,現在的問題是,爲什麼微軟設計的這種方式?

UPDATE:我的問題是相當:

爲什麼我不能直接調用構造函數在其他構造的結束,而我可以打電話開頭。

如果他們最後禁止撥打他們爲什麼不在開頭直接打電話呢?

+11

如何讓那些回答你這裏最後發表的帖子中引用的一些街頭信譽,並且你的前一個問題的回答:) – Jayden

+1

你可以問一個更具體的問題? 「爲什麼這樣設計?」是一個非常難以回答有意義的問題,因爲答案總是相同的:「因爲這似乎是最好的辦法」。面對數十個相互競爭的原則,設計總是一個妥協的過程,這些原則必須相互平衡。對於任何「這是爲什麼這樣設計的?」,都不會是一個簡單明瞭的答案。問題 - 一個適當的答案涉及對語言設計理念的深入而冗長的討論,我不準備在早上提供這個語言設計理念。 –

+0

@Jayden當然,我只需要重新閱讀以選擇哪一個我會標記爲最佳答案:) – programmernovice

回答

7

爲什麼我不能調用構造函數 直接轉 構造,而我可以打電話給AT THE 開始的結束。

好吧,讓我們把它分解成兩種情況。 (1)你正在調用「this」構造函數,(2)你正在調用「base」構造函數。

假設您處於第一種情況。這種情況下的典型使用模式是讓一堆ctors採用不同的參數,然後全部「喂」到一個完成所有實際工作的主ctor(通常是私有)。通常情況下,公共機構沒有自己的機構,所以在空塊之前或之後調用其他機構並沒有區別。

假設您處於第一種情況,並且您的在每個ctor中都有工作,並且您希望在除當前ctor的啓動之外的時間呼叫其他ctors。

在這種情況下,您可以通過將不同ctors所做的工作提取到方法中,然後以您喜歡的任何順序調用ctors中的方法,輕鬆完成此任務。這優於發明一種語法,允許您在任意位置調用其他ctors。有一些支持這一決定的設計原則。兩種是:

1)有兩種方法做同樣的事情會造成混淆;它增加了精神成本。在C#中,我們經常有兩種方法來做同樣的事情,但在這些情況下,我們希望通過讓事物的兩種不同方式成爲引人注目,有趣且功能強大的特性來「付出代價」利弊。 (例如,「查詢解析」與「流利查詢」是構建查詢的兩種截然不同的方式。)有辦法按照您調用任何其他方法的方式調用ctor似乎有兩種做某事的方式 - 調用初始化方法 - 但沒有引人注目或有趣的「收益」。

2)我們必須添加新的語言語法來完成它。新的語法花費很高;它的設計,實施,測試和記錄 - 這些都是我們的成本。但是它對你來說成本較高,因爲你必須學習語法的含義,否則你無法讀取或維護其他人的代碼。這是另一個成本;再一次,如果我們認爲客戶有明確的,引人注目的巨大收益,我們只會花費大量的語法增加。我在這裏看不到什麼好處。

總之,實現你想要的建築控制流很容易不添加功能做的,而且也沒有誘人的好處,以添加該功能。沒有新的有趣的代表權力被添加到語言。

對於「基地」的情況下,這是非常簡單的。你永遠不想在一個派生的構造函數之後調用一個基構造器。這是正常依賴規則的倒置。派生代碼應該能夠依賴於基礎構造函數設置了對象的「基礎」狀態;基本ctor不應該依賴派生構造函數設置派生狀態。

+0

我喜歡這種數學證明將不得不重新閱讀這一點,我們爲我的頭太滿,在這個星期我的工作,在工作中:) – programmernovice

+0

而且,新的C#4。0默認參數功能,我們將看到Eric首次調用「this」構造函數的需求在不斷減少。 –

1

我猜測,但也可能就這麼簡單:它是非常罕見你想要它,當你這樣做,通常有能充分勝任更好的選擇(私有/保護初始化方法)。並且沒有忘記初始化它的風險,或者調用依賴尚未初始化的數據的方法(爲什麼在ctor中調用virtual方法有點冒險)。

唯一需要注意的是,你不能使用readonly字段和ctor初始化方法,但是這比國際海事組織那些讓事情更復雜的角落案例更爲邪惡。

+0

這可能是非常罕見的,但即使這樣也會導致項目從其軌道上滑落。你能證明當你需要它時,有更好的選擇。 正如我在更新中說的那樣,實際上可以直接調用構造函數,但只能在開始時而不是結束時調用構造函數。那麼是不是真的因爲他們沒有打算實現一個很有用的特性,或者是因爲它是糟糕的設計? – programmernovice

1

構造函數的用途是初始化該對象。 當您想將一些初始參數傳遞給對象時,使用重載構造函數。

因此,設計的目的是讓一個Mega構造函數接受所有變量並進行所有初始化,並讓其他構造函數傳播變量,並將默認值設置爲不傳遞給用戶的參數。

這個想法是有一個單一的方法進行初始化,並沒有獨立的構造函數每個做別的。

+0

查看我的更新,因爲我的問題不夠精確。 – programmernovice

1

默認的構造函數只有在您沒有指定自己的構造函數時才由編譯器創建。這是一種語法糖,可以很容易地快速創建一個類。

通過編寫自己的構造函數,您實際上聲明是的,您對如何初始化對象感興趣。未生成默認構造函數。

由於禁用默認構造函數只能通過編寫另一個構造函數,允許用戶調用默認構造函數將使其無法禁用它。

+0

謝謝,必須重新閱讀才能理解。 – programmernovice

2

IIRC從C++的設計中,必須以自上而下的順序調用構造函數,因爲在構造函數完成執行之前,基類實例不保證可用。除非事先知道基礎對象已完全初始化並準備就緒,否則不能安全地構建派生對象。如果這看起來像一個小問題,考慮基類包含只在其構造函數中正確初始化的私有狀態的情況。 AFAIK的推理在CLR中是一樣的。

相同的推理適用於相反的方向。在派生類實例完成之後銷燬/終結基類實例是安全的,因爲派生對象可能依賴於基對象的狀態仍然有效。

+0

這個完整的答案好,謝謝,就可以了:) – programmernovice

3

我想爲你介紹的就是C#的規格在這裏中暗示行爲的技術原因:

http://en.csharp-online.net/ECMA-334:_17.10.3_Constructor_execution

任何變量初始化被稱爲構造函數代碼的一部分,如果你能打電話一個構造函數直接 - 從編譯器的角度來看這是一個非常特殊的函數 - 你可能會引發額外的行爲。通過構造函數鏈接方法(在構造函數定義中使用「:this」),編譯器尊重您嘗試安全地調用另一個構造函數。

我不認爲在同一個類中調用另一個構造函數並不需要太多的要求(不考慮繼承) - 沒有定義另一個函數是沒有辦法做到的,說實話,我更喜歡這樣做。如果我的構造函數變得冗長,我通常會感覺更舒適,因爲我經常需要在構造函數外部調用複雜的「Reset」或「Init」函數。

+0

會劃傷我的頭「沒有什麼你不能沒有定義其他功能做」,也沒有什麼不能用的程序設計也:) 事實上,當做我問,爲什麼我不能直接調用構造函數,我忘了細化和寧問: 爲什麼我不能直接另一個構造函數的最後調用構造函數,而我可以在一開始打電話。 – programmernovice

+0

但是,感謝看起來有趣的鏈接 – programmernovice

4

Eric Lippert有一個blog post關於創建對象時初始化器和構造函數的運行順序。他說:「派生得更多的構造函數可能依賴於由派生得較少的構造函數初始化的狀態,所以構造函數應該按照從基礎到派生的順序運行」。

+0

感謝您的鏈接,將它讀取 – programmernovice

+0

這真的很有道理。 –

相關問題