Tuesday, September 15, 2009

Understanding C# Class and Member Modifiers

Understanding C# Class and Member Modifiers
By Peter Aitken May 13, 2005
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.

The New ModifierThe New keyword is usually seen as an operator that is used to create new objects. It also plays a role as a modifier in class definitions and has a totally different meaning. It is used when you want a member of a derived class to hide a member of the same name in the base class. For example, here's a simple class:

public class A
public int total;

Suppose you want to derive a new class from A and give it a member called total that is type float. Here's where you need to use the new modifier:

public class B:A
new float total;

You don't see new used very often, for two reasons. First of all, omitting new does not prevent compilation; it just results in a warning. The class works as if you had included new — that is, the member in the derived class hides the same-name member in the base class. It can be included as an indication, perhaps to some maintenance programmer down the road, that you really did mean to include the member in the derived class even though the base class already had one of that name. Second, it is usually preferred to explicitly override the base class member using the override keyword.

I hope that this brief exposition has helped you to understand all these keywords and their uses. For convenience I have summarized this information in the following table and included the Visual Basic counterparts for each of the C# keywords.
C# Text Color
Class cannot be inherited (cannot be a base class).
Class cannot be instantiated but only used as based class and/or with abstract methods.
For class members: member is accessible only from the class in which it is declared. For classes: only allowed on nested classes to restrict access to the nested class to the containing class..
For class members: member is accessible only from types defined in the same assembly. For classes: class is accessible only from types in the same assembly.
For members: member is accessible from the class in which it is declared and from any class derived from that class.
Combines the access of Protected and Internal for a class member
Protected Internal
Protected Friend
Access is not restricted.
Hides a member inherited from a base class.

No comments: