Page 2 of 5
You can't do much with object-oriented programming without mastering access modifiers but it is still worth gathering the basic ideas here.
There are four access modifiers you can use to control which classes have access to properties and methods of another class:
There is also the combined modifier:
- public – access is allowed by any code no matter what class or assembly it belongs to.
- internal – as public but restricted to code in the same assembly
- protected – access is allowed by code in the same class or a derived class
- private – as protected but restricted to code in the same class.
- protected internal – access is allowed to any code in the same assembly or by any derived class in another assembly.
It is important to realise that private and protected are not code security measures. A private or protected method can be decompiled just as easily as a public method and reflection (when the code is running with full trust) can be used to call a private or protected method from any code.
This confusion between security and design is a general problem in considering any mechanism of inheritance control. It is tempting to always deny access to any code that you some how feel is proprietary and belongs to you even if it actually doesn't succeed in denying access and only makes it more difficult to get further value from your work.
This is about all there is to know about basic access modifiers together with the simple fact that no derived class can have a freer access modifier than its base class. If this wasn't the case what was supposed to be private could become public via a derived class.
As far as encapsulation is concerned the use of the modifiers is simple enough. Any property or method that is part of the class's interface with the outside world should be public. Public types can be accessed by the outside world and by classes derived from the class that they are declared in. Any internal mechanism that is strictly to be hidden from the outside world should be declared as either protected or private.
Protected versus private
The big problem is when should you use protected and when private?
The answer is often based on the simple question – do you want a programmer working on a class derived from your class to have access to its inner workings? This is a difficult question. Why would you refuse the use of a method say to a class's "end user" but not to a programmer who is creating a new class from your class? You might feel that a programmer who is capable of creating a new class is probably more technically capable of treating your method correctly – but this is an unlikely assumption.
In most cases the reason why you make a resource protected is because you, the implementer of the class, wants to derive new classes from it. After all, if you can't trust yourself to use resources you have created who can you trust? However, if you do this, notice that you also allow other programmers to do the same. It is also probably unreasonable to extend this privilege to yourself on the grounds that you can be trusted. In a few months' time the code in question will look as alien to you as it does to another programmer.
The decision about which code should be protected and which private should really relate to the code and not the coder. Public methods should define the external world's view of the class - they should define the way the class is used. In the same way private and protected methods should define the inner workings of the class. They are the resources that the class uses to get the job done.
To decide which should be private and which protected the important question is which of the methods are general tools that a derived class might also need to use as part of its extended implementation. In most cases any resource that a base class uses is probably needed by a class that extends it and so protected is most often appropriate – even if private is the default.
A simple example should make the situation clearer especially with reference to inheritance. Consider the class:
public class MyClass1
public void MyMethod1()
and a derived class:
public class MyClass2:MyClass1
public new void MyMethod1()
The overriding method in the derived class can both override and access the base class's method.
If you change MyClass1's MyMethod1 to protected everything still works as before – the overriding method can even remain public, i.e. code that can't call MyClass1's method can call MyClass2's.
If you change MyClass1's MyMethod1 to private, the call in MyClass2's method to the base class MyMethod1 no longer works. The derived class has no access to the parent's private resources. However, the derived class can create a method with the same name and there is no need for the "new" modifier as nothing is being overridden, i.e. the class doesn't inherit a MyMethod1 from the base class.
If you change MyClass1's MyMethod1 to virtual then it cannot be private as the whole point of a virtual method is to allow derived classes to override it dynamically. However you can make the method virtual protected and the derived class can either use the override or new modifier on its method.
If it uses the override modifier then the overriding method cannot be public – only protected as private is ruled out because the method is once again virtual. The reason that the protection level cannot change is that the compiler cannot work out if a reference to MyClass1 e.g.
is going to be referencing at run time an object of type MyClass1 or of type MyClass2.
Now consider the method call:
If MyMethod1 is virtual then which method will be called depends on the runtime type of myObj and if the protection levels were different the compiler could not work out at compile time if the method was or was not accessible.
Notice that if the method isn't declared as virtual then this problem doesn't arise because early binding means that no matter what class myObj references the method defined in MyClass1 is called – because that's the declared type of myObj.
For this reason if you declare the derived class's method as new then it can be public, private or protected. This is once again reasonable as the new modifier "kills" the virtual inheritance, i.e. it works as if MyClass1's method wasn't declared as virtual.