簡體   English   中英

“C#深度”中的抽象類實例化

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM