Understanding C# Class and Member Modifiers

By Kuristosu Dei
Dev Source, May, 2005 by Peter Aitken
In my opinion, one of the best things about programming in C# is the ability to use true object-oriented techniques. But let's face it — for those of us who were brought up with procedural programming (and I bet that's just about 100% of us!), getting your mind wrapped around the concepts of OOP can be tough. It is not made any easier by all those strange-sounding keywords that can be used when defining classes and class members. Friend? Sealed? Abstract? Pass the aspirin! In this article, I try to bring some clarity to this topic.

Access Modifiers

Some of the keywords you use with classes are access modifiers. In other words, they control the extent to which the class is available to code (similar to variable scope). For example, look at this code which creates, or attempts to create, an instance of the class MyClass:

MyClass cls = new MyClass();

If MyClass is accessible at the location where this code is located, there is no problem. If MyClass is not accessible, you get a compile error, to the effect that the type MyClass cannot be found.

Additional confusion comes from the fact that some of the access modifiers can be used with class members (methods, for example) as well as with the classes themselves. Let's take a look at these access modifier keywords, first as they apply to classes and then as they apply to class members.

Class Access Modifiers
The default class access modifier is internal. This makes the class accessible from other classes in the same assembly. By default, I mean that this is the access provided if you include no access modifier keyword. Thus, these two are equivalent:

class MyClass { ... }

internal class MyClass { ... }

The default internal access is appropriate for the vast majority of classes you will create.

Less restrictive access is provided by the public keyword. A public class is accessible without restriction. In practical terms, it means that a public class in one assembly is accessible from another assembly:

public class MyClass { ... }

The most restrictive class access is created with the private keyword. You can use private only with a nested class, one that is defined within another class. The result is that the private class is accessible only from within the containing class:

public class OuterClass
{
...
private class InnerClass
{
}
}

Member Access Modifiers

By default, class members are private, which means they are accessible only from code in the class. You can include the private keyword or omit it with the same effect:

SomeMethod() { ... }
private SomeMethod() { ... }

Slightly less restrictive is protected access, obtained with the (you guessed it) protected keyword. A protected member is accessible in the type in which it is defined and in types derived from that type:

protected SomeMethod() { ... }

Thus, if you create a protected member in class A and then create class B that inherits from A, the member will be available to code in class B.

Internal access means the member is accessible to other types that are defined in the same assembly:

internal SomeMethod() { ... }

You can combine the protected and internal keywords to provide member access that is a combination of the two:

protected internal SomeMethod() { ... }

The least restrictive access is obtained with the public keyword. Use the public keyword to make a class member freely accessible inside and outside of the class.

public internal SomeMethod() { ... }

Other Class Modifiers

Some class modifiers are not related to access at all but place limitations on inheritance and instantiation. By default, a class can be instantiated — in other words, you can create an object from it — and it can also be used as the base class for a new class. You can modify this with the abstract and sealed keywords.

A class defined using the abstract keyword cannot be instantiated. Thus if you have a class definition like this :

abstract class MyClass { ... }

you cannot do this:

MyClass cls = new MyClass(); // Causes compilation error.

Abstract classes are usually created to serve as base classes. The .Net Framework itself contains many base classes. For example, your program may need three classes that have many members in common, but differ in a few crucial details. A good programming strategy would be to create an abstract class that contains all the common elements, then create the three individual classes that each inherits from the abstract class. Abstract classes can also be used to provide functionality without data storage, such as the Math class in the .Net Framework.

A sealed class is sort of the opposite of abstract. It can be instantiated but cannot serve as a base class. The primary reason to seal a class is to prevent your users from fiddling around with it and breaking it (and of course blaming you, usually!). It's also the case that sealing a class permits certain compiler optimizations that are not possible with non-sealed classes. Obviously, a class cannot be both sealed and abstract.
 

0 comments so far.

Something to say?