Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract class instantiation in 'C# in depth'

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?

like image 719
Aage Avatar asked Oct 22 '13 13:10

Aage


People also ask

Can you instantiate abstract class?

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 .

Why can't we instantiate an abstract class in C?

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.

Can I instantiate abstract class C#?

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.


4 Answers

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.

like image 156
Tim S. Avatar answered Oct 17 '22 04:10

Tim S.


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.

like image 24
Dan Puzey Avatar answered Oct 17 '22 04:10

Dan Puzey


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.

like image 3
StuartLC Avatar answered Oct 17 '22 04:10

StuartLC


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.

like image 1
Daniel A.A. Pelsmaeker Avatar answered Oct 17 '22 04:10

Daniel A.A. Pelsmaeker