[英]Abstract class instantiation in 'C# in depth'
我正在閱讀Jon Skeet目前正在閱讀的“C#深度”,並且有一個示例描述代碼合同,其中一個抽象類實現了一個接口,該接口具有作為接口的附帶類,代碼合同的術語:'Contract Class For'(我不會在這里詳細介紹代碼合同的運作方式。
界面(第467頁):
[ContractClass(typeof(ICaseConverterContracts))]
public interface ICaseConverter
{
string Convert(string text);
}
抽象類:
[ContractClassFor(typeof(ICaseConverter))]
internal abstract class ICaseConverterContracts : ICaseConverter
{
public string Convert(string text)
{
Contract.Requires(text != null);
Contract.Ensures(Contract.Result<string>() != null);
return default(string); // returns dummy value
}
// prevents instantiation
private ICaseConverterContracts() { }
}
(我根據書中的評論在代碼中添加了注釋)
我的問題:
當你無法實例化一個抽象類時,為什么有必要將私有構造函數添加到這個抽象類? 我得不到什么?
雖然abstract
類無法直接實例化,但構造函數上的訪問修飾符(例如private
)在繼承時很重要。 通過使構造函數為private
而不是默認值,您可以創建它,以便不能構造任何繼承的類。 由於這是唯一的構造函數,因此您無法有效地使類sealed
,因為沒有繼承類(除非它嵌套在ICaseConverterContracts
)可以編譯(至少在C#中)。
我猜測Code Contracts代碼通過反射實例化類,或者繞過構造函數private
其他方式。
將構造函數標記為私有也會阻止任何派生類被實例化:
public class Foo : ICaseConverterContracts
{
public Foo() // does not compile as the base class constructor is inaccessible
{
}
}
這明確阻止您在任何情況下實例化ICaseConverterContracts
類,因為它不是應該實例化的類。
ContractClassFor
是接口的虛擬類實現,除了發布接口對其消費者要求和承諾的合同之外沒有其他目的。 從相應的ContractClass
可以看出,接口及其契約類是緊密耦合的。 (這個相當尷尬的實現可能是因為合同無法直接在接口上發布,因為接口上不允許實現)。 然后對底層接口的所有real
實現強制實施偽ContractClassFor
中的ContractClassFor
(另請注意,只有ContractClassFor
虛擬實現能夠發布接口的合同 - 否則不同的實現可能會有不同的合同,這實際上沒有意義。)
ContractClassFor
類永遠不會被實例化,你經常會發現虛擬實現只是為了讓編譯器進行編譯,例如
public string Convert(string text)
{
Contract.Requires(text != null);
Contract.Ensures(Contract.Result<string>() != null);
return default(string); // returns dummy value
}
要么
public string Convert(string text)
{
Contract.Requires(text != null);
Contract.Ensures(Contract.Result<string>() != null);
throw new NotImplementedException();
}
等等
當您的契約類描述沒有無參數構造函數的類時 ,您需要指定構造函數。 否則,完全沒必要。 由於Code Contracts已經涉及很多打字, 我建議你不要使用私有構造函數 。
私有構造函數阻止繼承,因為派生類無法調用基類構造函數。
但是,由於Code Contract Rewriter從您的代碼中刪除了所有這些類。 ICaseConverterContracts
將不存在於已編譯的程序集中。
您的ICaseConverterContracts
類將顯示的唯一位置是bin/Debug/CodeContracts/MyProject.Contracts.dll
中的contract程序集。 但是該程序集僅適用於靜態驗證程序:您永遠不會直接使用它,甚至不會引用它。 因此,在那里擁有私有構造函數也不是必需的。
我能想到為什么Jon Skeet將其包含在他的代碼中的唯一原因是向其他人發出信號,告訴他們該類不是要實例化的代碼。
擁有私有構造函數意味着您無法從該類繼承。
該行為類似於sealed
類的行為,除了該類仍然可以由嵌套類繼承。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.