Question

I'm reading 'C# in depth' by Jon Skeet currently and there's an example depicting Code Contracts with an abstract class implementing an interface which features as an accompanying class for the interface, in Code Contracts' terms: a 'Contract Class For' (I'm not going into details about the workings of Code Contracts here).

The interface (p. 467):

[ContractClass(typeof(ICaseConverterContracts))]
public interface ICaseConverter
{
    string Convert(string text);
}

The abstract class:

[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() { }

}

(I've added the comments in the code based on comments in the book)

My question:

Why is it necessary to add the private constructor to this abstract class when you can't instantiate an abstract class to begin with? What am I not getting?

Was it helpful?

Solution

While abstract classes can't be directly instantiated, the access modifier (e.g. private) on the constructor matters when they are inherited. By making the constructor private instead of the default, you are making it so that no inherited class can be constructed. Since this is the only constructor, you are effectively making the class sealed, since no inheriting class (unless it's nested in ICaseConverterContracts) can compile (in C#, at least).

I'm guessing that the Code Contracts code instantiates the class via reflection, or some other way that bypasses the problem of the constructor being private.

OTHER TIPS

Marking that constructor as private prevents any derived class from being instantiated, too:

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

This explicitly prevents you from instantiating the ICaseConverterContracts class under any circumstance, as it's not a class that should ever be instantiated.

The ContractClassFor is a dummy class implementation for the interface, with no other purpose than to publish the contracts that the interface demands from, and promises to, its consumers. As can be seen from the corresponding ContractClass, the interface and its contract class are tightly coupled. (This rather awkward implementation is presumably is because the contracts can't be published directly on the interface, as there is no implementation allowed on an interface). The contracts in the dummy ContractClassFor are then enforced for all real implementations of the underlying interface (Also note that only the ContractClassFor dummy implementation is able to publish contracts for the interface - otherwise different implementations could have different contracts, which wouldn't really make sense.)

The ContractClassFor class is never instantiated, and you will often find dummy implementations just to get the compiler to compile, e.g.

public string Convert(string text)
{
     Contract.Requires(text != null);
     Contract.Ensures(Contract.Result<string>() != null);
     return default(string); // returns dummy value
}

or

public string Convert(string text)
{
     Contract.Requires(text != null);
     Contract.Ensures(Contract.Result<string>() != null);
     throw new NotImplementedException();
}

etc.

You need to specify a constructor when your contract class describes a class that doesn't have a parameterless constructor. Otherwise, it is completely unnecessary. And since Code Contracts already involve a lot of typing, I suggest you leave the private constructor out.

The private constructor prevents inheritance, as the derived class cannot call the base class constructor.

But since the Code Contract Rewriter removes all these classes from your code. ICaseConverterContracts will not exist in the compiled assembly.

The only place where your ICaseConverterContracts class will show up is in the contracts assembly in bin/Debug/CodeContracts/MyProject.Contracts.dll. But that assembly is only for the static verifier: you'll never use it directly, or even have a reference to it. So having a private constructor in there is also not required.

The only reason I can think of why Jon Skeet included it in his code is to signal to other people reading the code that the class is not meant to be instantiated.

Having a private constructor means you can't inherit from that class.

The behavior is similar to that of a sealed class, except the class can still be inherited by nested classes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top