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?
Abstract classes cannot be instantiated, but they can be subclassed. When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class. However, if it does not, then the subclass must also be declared abstract .
We can't instantiate an abstract class because the motive of abstract class is to provide a common definition of base class that multiple derived classes can share.
An abstract class cannot be instantiated. An abstract class may contain abstract methods and accessors. It is not possible to modify an abstract class with the sealed modifier because the two modifiers have opposite meanings.
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With