繁体   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