“C#深度”中的抽象类实例化

时间:2013-10-22 13:51:03

标签: c# code-contracts

我正在阅读Jon Skeet目前正在阅读的“C#深度”,并且有一个示例描述代码合同,其中一个抽象类实现了一个接口,该接口具有作为接口的附带类,代码合同的术语:'合同类对于'(我不会在这里详细介绍代码合同的运作方式)。

界面(第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() { }

}

(我已根据书中的评论在代码中添加了评论)

我的问题:

为什么在无法实例化抽象类时,有必要将私有构造函数添加到此抽象类中?我没得到什么?

5 个答案:

答案 0 :(得分:14)

虽然abstract类无法直接实例化,但构造函数上的访问修饰符(例如private)在继承时很重要。通过使构造函数private而不是默认值,您可以创建它,以便不能构造任何继承的类。由于这是唯一的构造函数,因此您实际上是在创建类sealed,因为没有继承类(除非它嵌套在ICaseConverterContracts中)可以编译(至少在C#中)。

我猜测Code Contracts代码通过反射实例化类,或者绕过构造函数为private的其他方式。

答案 1 :(得分:7)

将构造函数标记为私有也会阻止任何派生类被实例化:

public class Foo : ICaseConverterContracts
{
    public Foo()  // does not compile as the base class constructor is inaccessible
    {
    }
}

这明确阻止您在任何情况下实例化ICaseConverterContracts类,因为它不是应该实例化的类。

答案 2 :(得分:3)

ContractClassFor是接口的虚拟类实现,除了发布接口要求并承诺其消费者的合同之外别无其他目的。从相应的ContractClass可以看出,接口及其契约类是紧密耦合的。 (这个相当尴尬的实现可能是因为合同无法直接在接口上发布,因为接口上不允许实现)。然后,对基础接口的所有ContractClassFor实现强制执行伪real中的合同(另请注意,只有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();
}

答案 3 :(得分:1)

当您的合同类描述没有无参数构造函数的时,您需要指定构造函数。否则,完全没必要。由于代码合同已涉及大量输入,我建议您将私有构造函数排除在外

  

私有构造函数阻止继承,因为派生类无法调用基类构造函数。

但是,由于Code Contract Rewriter从您的代码中删除了所有这些类。 } 在编译的程序集中不存在

ICaseConverterContracts课程出现的唯一地方是ICaseConverterContracts中的合同大会。但是该程序集仅适用于静态验证程序:您永远不会直接使用它,甚至不会引用它。因此,在那里拥有私有构造函数也不是必需的。

我能想到为什么Jon Skeet将其包含在他的代码中的唯一原因是向其他人发出信号,告诉他们该类不应该被实例化的代码。

答案 4 :(得分:0)

拥有私有构造函数意味着您无法从该类继承。

该行为类似于sealed类的行为,但该类仍然可以由嵌套类继承。