Pop Quiz: Declared Accessibility in C#

What are the access modifiers available in C#?
Public, internal, protected, protected internal or private.

What is the difference between "protected" and "internal"?
Protected means within the same inheritance chain, internal means within the same assembly.

What access modifiers can be used against non-nested classes in C#?
Public or internal - the same goes for Interfaces. Note that non-nested classes cannot be private since it makes no sense for such classes to be private.

What access keywords can be used against nested classes in C#?
Public, internal or private.

What is the default accessibility of classes in C#?
Internal is the default if no access modifier is specified for a class and also for interfaces.

What access modifiers can be used against class members in C#?
Public, internal, protected, protected internal or private.

What is the default accessibility of class members in C#?
Private. Same goes for struct members.

Can you add access modifiers to interface members?
NO. The point of an interface is to describe a contract between an implementing type and users of the interface. Outside callers aren't going to care and shouldn't have to care about implementation. If an interface is public then every part of that contract has to be public, otherwise it would mean one thing to friend/internal classes and a different thing to everything else. If you need default implementation then it's best to use an abstract class.

Can you add access modifiers to Enum members?
NO. Enum members are always public, and so no access modifiers can be applied.

Does the "protected internal" access modifer mean OR or AND?
It means protected **OR** internal. Not both.

What is an "inconsistent accessibility" error?
A derived class, or a member function in another class that returns a type cannot expose a type with greater visibility than that defined in the class itself. It is a sign of a faulty design if this situation happens and the compiler tells you so.

What access modifiers can be used against structs in C#?
Public or internal. This is the same as non-nested classes.

What access modifiers can be used against struct member functions in C#?
Public, private, or internal. Note that struct members cannot be declared as protected because structs do not support inheritance.

How is a "Friend Assembly" created?
You can enable specific other assemblies to access your internal types by using the InternalsVisibleToAttribute. This attribute is applied to the AssemblyInfo.cs file of the assembly granting the permission, and takes a parameter indicating the assembly receiving the permission. Note that private member functions and types will still remain inaccessible to the friend assembly.

What access modifiers can be used against instance constructors in C#?
Any of the 5. Public, internal, protected, protected internal or private.

What access modifiers can be used against class destructors in C#?
None. It's not your call dude! The garbage collector owns this puppy.

What access modifiers can be used against user-defined operators in C#?
Only public. It makes no sense to redefine an operator for a given class or struct and then have an access modifier other than public on it.

What access modifiers can be used against delegates in C#?
The public, protected, internal, and private modifiers control the accessibility of the delegate type. Depending on the context in which the delegate declaration occurs, some of these modifiers may not be permitted.

What is the default accessibility of delegate types in C#?

Can namespaces have access modifiers?
No. All namespaces are implicitly public.


Pop Quiz: Applied Object-Oriented Principles with C#

Q1: Does C# allow classes to have multiple inheritance?

C# allows you to to have multiple interface inheritance, but it does NOT allow you to have multiple implementation inheritance like C++. Get over it - this design decision actually makes things easier most of the time.

Q2: Can you add static methods to an interface?  

NO. Although other languages like PHP have this (Late Static Binding), in C# the designers stuck with the OOP principle that interfaces define behaviour of instances - that is they define a contract but not the implementation, hence static methods should be excluded. Java also prevents this. From a technical standpoint it is certainly possible for both Java and C# to add this feature but I suspect the respective language designers would need to be convinced before that happens.

Q3: Can you add operator overload definitions to an interface?

NO because operator overload definitions are static methods and static methods are not allowed in interfaces.

Q4: Can you add accessibility modifiers to interface members?  

NO. The point of an interface is to describe a contract between an implementing type and users of the interface. Outside callers aren't going to care and shouldn't have to care about implementation. If an interface is public then every part of that contract has to be public, otherwise it would mean one thing to friend/internal classes and a different thing to everything else. If you need default implementation then it's best to use an abstract class.

Q5: What's the difference between explicitly and implicitly implemented interfaces?

Unlike C++, in C# we can implement an interface implicitly as well as explicitly. Explicitly implemented interfaces are only available when the instance is cast to that interface. In contrast, implicit interfaces are available via the instance and via a cast of the instance to the interface in question. Explicit interfaces also help skirt the classic diamond problem associated with multiple inheritance and they are allowed to be private if necessary, but they cannot be virtual or abstract. Implicitly implemented interface member functions can be virtual or abstract, but they have to be public.

Q6: Can you define a default, parameterless constructor for a struct? 

NO. Structs provides value-type semantics, while classes provide reference-type semantics. So for efficiency in creating a struct, the rule adopted by the C# team was "the default value for any type can't rely on any initialization". Instead, the C# team resorted to the same trick they use to default value and reference types - doing a bitwise zeroing of the storage location. This results in 0 being assigned to value types used in structs and you can't do anything in the default constructor to change this since you're prevented from creating one.

Q7: Can structs implement interfaces?

Yes they can, but beware - when you cast a struct to an interface it implements you are implicitly boxing the struct since the interface reference is a reference type. This can lead to subtle issues in code as can be seen here.

Q8: Can structs be sub-classed?

NO they are implicitly sealed.

Q9: What sort of static constructors are you allowed to define on non-static classes?

Only a parameterless one - with the same name as the class obviously. Why? Well, a static constructor is run once per type, rather than once per instance, and it is guaranteed to run before any instances of the class are created, before any other static methods are accessed, but after static field initialization occurs although we don't know exactly when it runs - that part is non-deterministic. Since we don't explicitly call the constructor there is no way for the programmer to pass in parameters which is why the compiler ensures you don't waste your time writing static constructors that take parameters.

Q10: Can static constructors of non-static classes be called explicitly?

NO. They are only ever called implicitly by the runtime, and the timing of these calls is non-deterministic.

Q11: Can static classes be sub-classed?

NO. Static classes are implicitly sealed.

Q12: What is meant by the statement "References in C# are polymorphic"?

It means that a reference to a base class can point to an instance of a sub-class. That allows the developer to have methods parameters defined as the base type which accept any sub-class of that base type! Extremely handy.

Q13: Why is calling virtual-methods in a constructor a bad thing?

Consider the case where you have a base class and a derived class and the constructor of the base class calls into a virtual method which is defined in the base class but also overridden by the derived class. In C++, the base class is guaranteed to be created before the derived class so when the constructor of the base class is run it sees the most derived function as the one it has defined. In C# the base class constructor will also run before the constructor of the derived class but calls to virtual methods are always passed to the most derived version which will be the overridden function in the derived class. The problem with this is that the derived class has not been fully initialized at this point and it's constructor hasn't even been run. This is because initializers run in the opposite order as constructors. The fact that the derived class running the virtual override is not fully initialized leads to subtle side-effects that confuse the hell out of people and eventually breaks code. For these reasons it's good practice to avoid calling virtual methods from constructors, unless the class is sealed. IMHO this is one behavior where C++ is more intuitive than C#.

Q14: Is an overridden class member virtual? 

YES. If B is a sub-class of A and overrides a virtual function in A, the function can be overridden again by C, a sub-class of B. This pattern exists unless you use "override sealed" which is equivalent to the "final" keyword in Java - it prevents further overriding thus ending the virtual chain for that specific method.

Q15: Are instance members virtual or non-virtual by default in C#?

Non-virtual. Interestingly, unlike C# which requires the virtual keyword, instance methods in Java are virtual by default. C# went against this for performance and versioning reasons. They figured Java developers often forget to use the final keyword.

Q16: Can you declare a virtual static method in C#? 

NO. Makes no sense. To quote Eric Lippet... the core design principle of static methods, the principle that gives them their name, states that static methods can always be determined exactly, at compile time, what method will be called. That is, the method can be resolved solely by static analysis of the code. Virtual is the exact opposite - the virtual keyword tells the compiler that the method to be called will be determined at run time and based on run time type information.

Q17: Can you have abstract static methods in C#?

No. Abstract methods are implicitly virtual so the same argument applies as given above. See Section 10.6.6 in the C# spec... "When an instance method declaration includes an abstract modifier, that method is said to be an abstract method. Although an abstract method is implicitly also a virtual method, it cannot have the modifier virtual."

Q18: Does the "protected internal" access modifer mean OR or AND?

protected **OR** internal. Not both.

Q19: Can you override static methods in sub-classes?

No - in both Java and C#. It makes no sense to have virtual and overridden static methods.

Q20: Can abstract and virtual methods of a class be marked as private?

No because it makes no sense. The purpose of virtual and abstract methods is to permit/force a derived class to override the base functionality. Hence allowing these to be private defeats that purpose and is disallowed. Note that abstract methods are implicitly virtual.

Q21: Which of these must be done explicitly: upcasting to a base class, or downcasting to a derived class?

Downcasting to a derived class. Since upcasting to a base class is a safe operation that is guaranteed to work it is done implicitly. Conversely, downcasting is not a safe operation which is why the compiler requires you to do it as an explicit cast so it is clear on your intent.

Q22: When you upcast a reference type what happens to the object instance that you apply the cast to?

Nothing. Casting affects only the references. The object instance is not touched.

Q23: Do sub-classes automatically expose the same constructors as their base types?

NO, you have to manually re-declare them.

Q24: Does C# support covariant return types?

NO it doesn't - that's a CLR restriction, not something specific to C# - but they can be simulated using explicit, generic interfaces. Bill Wagner has a good article on that here. This is definitely one thing C++ developers find frustrating when moving over to C# since covariant return types are supported in C++ and Java. [According to this, Microsoft has no plan to change this in the future, however C# 4.0 is planned to allow co- and contra-variance on parameterized interface and delegate types.]

Q25: Can you declare a generic property in C#?

NO, only methods and types can introduce new generic parameters. Properties can of course use existing generic parameters defined in the containing class.

Q26: How do you define a concrete class that implements both an interface and a base class in C#?

You need to specify the base class first after the colon before listing any interfaces implemented.


Design Guidelines Part.3: The Liskov Substitution Principle

LSP was defined way back in 1988 by Dr. Barbara Liskov, who incidently won the 2009 Turing Award, perhaps the most prestigious award in computer science. Her original definition was:

“If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.”

But Robert Martin offered a much more terse definition:

Subtypes must be substitutable for their base types

What this is saying is that a derived class should honor the contracts made by it's parent classes. In other words, if a method signature accepts a base class reference, then it should be able to accept an instance of any class derived from that base class without affecting the functioning of the method.

Object-oriented programmers will be familiar with the concepts of abstraction and polymorphism. In statically-typed O-O languages, like C++, Java and C#, the key mechanism to achieve polymorphism is inheritance. LSP is a guiding principle that restricts how inheritance is used such that the OCP is not violated.

Technically speaking, the type of polymorphism this principle addresses is inclusion polymorphism. Inclusion polymorphism occurs in languages that allow subtypes and inheritance whereby an instance of a subtype can be manipulated by the same functions that operate on instances of the supertype (parent class type). This implies a reference (or pointer) of the parent class type can also refer to any child object, meaning that the type of the object being referred to must be determined at runtime. Since the type of object cannot be determined until runtime, and virtual methods are defined per type, it implies that a method call may be executed either in the parent or the child class and this dispatch decision cannot be made until runtime.

The Liskov Substitution Principle helps to guarantee inclusion polymorphism, which is a good thing because inclusion polymorphism improves reuse. All code that references the superclass can be reused referencing a subclass.

Why Follow It?
By adopting the LSP, the correctness of a method accepting base class references is guaranteed under certain substitutability conditions. Furthermore, since LSP is actually a special case of the Open-Closed Principle, every time you violate the LSP, you violate the OCP as a result - but not the other way round. It is this relationship between OCP and LSP that makes it easier to spot since developers tend to understand OCP much more readily that they do with LSP.

Say you develop a class hierarchy using inheritance, and you have a method in your base class that accepts a base class reference, and when you pass in a derived class reference you get unexpected results, it's a strong sign that the inheritance chain and the object model is incorrect. You need to remember that a class must fulfill an "is-a" relationship in order for it to be able to inherit from another class. This relationship is about behavior not data! In this sense, LSP is good at exposing faulty abstractions.

LSP is the reason that it is hard to design and create good deep hierarchies of sub classes and the reason to consider using composition over inheritance. (The strategy pattern is a prototypical example of the flexibility of composition over inheritance.)

The whole point of the Liskov Substitution Principle is really to make you think clearly about the expected behavior and expectations of a class before you derive new classes from it.

Obligatory Example
Common examples for violation of LSP are Rectangle::Square, Circle::Ellipse, etc. Rather than reproduce those here, take a look at the examples in Robert Martin's paper.

Design By Contract
The Liskov Substitution Principle is closely related to the design by contract methodology, which provides rules telling us the conditions under which it is acceptable to substitute a derived class for a base class:

  • Preconditions cannot be strengthened in a subclass.
  • Postconditions cannot be weakened in a subclass.

In other words, a sub-type can only have weaker pre-conditions and stronger post-conditions than its base class. Put differently...derived methods should expect no more and provide no less.

Signs of LSP violations include:

  • A subclass that does not keep all the external observable behavior of it's parent class
  • A subclass modifies, rather than extends, the external observable behavior of it's parent class.
  • A subclass that throws exceptions in an effort to hide certain behavior defined in it's parent class
  • A subclass that overrides a virtual method defined in it's parent class using an empty implementation in order to hide certain behavior defined in it's parent class

Method overriding in derived classes is probably the biggest cause of LSP violations. All method overrides should be done with great impunity as to avoid these violations.

In addition, the principle implies that no new exceptions should be thrown by methods of the subclass, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the superclass. (think: co-variance and contra-variance).

A function using a class hierarchy violating the principle uses a reference to a base class, yet must have knowledge of the subclasses. Such a function violates the open/closed principle because it must be modified whenever a new derivative of the base class is created, and that really sucks because the compiler or your existing unit tests won't find these cases for you - you have to become a UN weapons inspector, remember what things exactly you need to look for, and go hunt them down manually!

Final Advice
In the words of Robert Martin, Agile Principles, Patterns and Practices in C# (P.149):

"A good engineer learns when compromise is more profitable than perfection. However, conformance to LSP should not be surrendered lightly. The guarantee that a subclass will always work where its base classes are used is a powerful way to manage complexity. Once it is forsaken, we must consider each subclass individually."

Other Parts in the Series
Design Guidelines Part.1: Single Responsibility
Design Guidelines Part.2: Open-Closed Principle
Robert Martin's Original Paper

Next »