C# Modifiers

Summary

Introduction

Modifiers are C# keywords used to modify declarations of types (class, struct, interface, enum) and type members (fields, properties, methods, indexers, ...). The remaining sections explain these modifiers.

Access Modifiers

Access modifiers are keywords used to specify the declared accessibility of types and type members. The four access modifiers are discussed in the table below:

Access Modifier Meaning
public public is an access modifier for types and type members. This is the most permissive access level as there are no restrictions on accessing a public type or type member.
internal internal is an access modifier for types and type members. internal members are accessible only within file of the same assembly. It is an error to reference an internal type or internal type member outside the assembly within which it was declared.

A common use of internal access is in component-based development because it enables a group of components to interact in a private matter without being exposed to the outer world. For example, a Data Access Layer could have several classes with internal members that are only used by the DAL.
protected protected is an access modifier for type members only. A protected member is only accessible within the body of the containing type and from within any classes derived from the containing type.
private private is an access modifier for type members only. private access is the least accessible and such members are only accessible within the body of the containing type.

Note that nested types within the same containing body can also access those private members.

Accessibility Levels

The four access modifiers listed above result in five accessibility levels shown below. Note how certain accessibility levels are not permitted depending on the context in which an access modifiers was used:

Accessibility Level Meaning Applies to namespaces Applies to Types Applies to Type members
public Access is not restricted. Yes Yes Yes
internal Access is limited to the current assembly (project). No Yes Yes
protected Access is limited to the containing class, and classes derived from the containing class No No Yes
internal protected Access is limited to the current assembly (project), the containing class, and classes derived from the containing class No No Yes
private Access is limited to the containing type. No No Yes

The following table illustrates accessibility levels for namespaces, types, and type members. Note that namespace elements (i.e., classes, structs, interfaces and enum) can only have public or internal declared accessibility. Access modifiers private, protected,  and protected internal are not allowed on namespace members. 

Context Default Accessibility Allowed Declared Accessibility Default Member Accessibility Allowed Declared Accessibility On Members
namespace public None Internal public
internal
class internal (if top level) public
internal
private public
protected
internal
internal protected
private
interface internal (if top level) public
internal
public None
struct internal (if top level) public
internal
private public
internal
private
enum internal (if top level) public
internal
pubic None

abstract

Applies To: Classes, methods, and properties.

The meaning of the keyword abstract depends on the context in which it is used. The abstract keyword can be used in three contexts:

Abstract Classes

An abstract class means that the class is intended to be used as a base class only. Note the following features of abstract classes:

public abstract class Person
{
    ... 
}

Abstract Methods and Properties

An abstract method or property means that the method (or property) does not have an implementation. Note the following features of abstract methods and properties:

The following class illustrates the above points:

public interface IFile
{
    void Open();
    void Close();
}

public abstract class Folder : IFile
{
    // Data members
    long lSize;

    // Interface members must be implemented, even if the containing class is abstract
    public void Open() { Trace.WriteLine( "IFile.Open" ); }
    public void Close() { Trace.WriteLine( "IFile.Close" ); }

    // Abstract members and properties
    public abstract void RenameFolder();
    public abstract string FolderName
    { 
        get;
        set;
    }

    // Non-abstract methods/properties
    public long FolderSize
    {
        get { return 0; }
        set { lSize = value; }
    }
}

public class WindowsFolder : Folder
{
    // Data members
    string strFolderName; 

    // Implement inherited abstract methods
    public override void RenameFolder()
    {
        Trace.WriteLine( "WindowsFolder.RenameFolder" );
    }

    public override string FolderName
    { 
        get { return strFolderName; }
        set { strFolderName = value; }
    }
}

const

Applies To: fields and member variables.

The keyword const is used to modify the declaration of a field or local variables. It indicates that the value of the field or local variable cannot be modified. Note the following two points for using const:

public class ClassWithConstants
{
    // const is applied to fields.
    private const double PI         = 3.14;             // A const
    private const double CM_To_Inch = 2.54;             // A const
    private const double Inch_To_CM = 1 / CM_To_Inch;   // A const can participate in a const expression
    private const string USER      = null;              // reference types must be initialized either to null or to a string

    public void ConvertFromEnglishToMetric()
    {
        // const can also be applied to local variables
        const double Meter_To_Inch = CM_To_Inch * 100;

        ...
    }
}

extern

Applies To: Method, property, event, indexer, operator, constructor, and destructor 

The extern modifier is used in a class member declaration (method, property, event, indexer, operator, constructor, and destructor ) to indicate that the method is implemented somewhere else outside the C# code (externally). extern is usually used with the DllImport attribute. And because an extern method should not provide an implementation, there is no method body. For example:

public class MyClass
{
    [DllImport("User32.dll")]
    public static extern GetDirectoryName( out string strDirName );

    public void ShowDirectoryName()
    {
        string sName;
        GetDirectoryName( out sName );       // Use the extern method just like any other C# method
        return sName;
    }
}

See External Methods in Classes section.

It is an error to use extern and abstract modifiers to modify the same member. abstract modifier means that the method implementation is not provided in the containing class but should be provided in derived class, whereas extern means that the method is implemented outside the C# code.

External Assembly Alias (New in C# 2.0)

Sometimes you may have to use two or more versions of the same assembly in the same application. In other words, you need to reference two versions of the same assembly that have the same fully-qualified name. By using an external assembly alias, the namespaces of each assembly can be wrapped inside root-level namespaces named by the alias, allowing them to be used in the same file.

External assembly aliases are accomplished with the alias sub-option of the /Reference compiler option. The main procedure is as follows: Suppose you have a Data Access Layer project called DAL written in VB. You compile this project to produce DAL_VB.DLL. This DLL is in turn used by a business objects layer DLL called BOL.DLL. You then rewrite DAL in C# but only manage to partially finish it. This partially finished code is now in a DLL called DAL_CS.DLL. Both DAL_VB.DLL and DAL_CS.DLL refer to the code base which has the same namespaces. In your BOL.DLL you still would like to reference both DLLs - DAL_CS.DLL for the new and improved functionality, and DAL_VB.DLL for the remaining yet-to-translate functionality.

You then compile your BOL.DLL with the /Reference option as follows:

/Reference DALVB=DAL_VB.DLL /Reference DALCS=DAL_CS.DLL

This will setup two external references called DALVB and DALCS, which you can use in the BOL code via an extern statement as follows:

extern DALVB;
extern DALCS;

// You can now refer to the same class from both DLLs
DALVB.DAL.ExecuteNonQuery( ... );            // Old DLL
DALCS.DAL.ExecuteNonQuery( ... );            // New DLL

override

Applies To : Method, property, event, indexer.

An override class member provides a new implementation for a member derived from a base class. Note the following points:

See Virtual Methods in Classes section for a full example.

Partial (C# 2.0)

Applies to: classes, structs and interfaces. Does not apply to delegate and enums.

partial keyword is used to split the definition of a class or struct or interface across multiple source files. Each source file would contain a section of the class definition and all parts are combined when the application is compiled. The following example illustrates:

// File1.cs
public partial class Order
{
    private GetOrderDetails() { ... }
}

// File2.cs
public partial class Order
{
    public RetrieveOrder()
    {
        GetOrderDetails();
        ...
    }
}

 Using partial is desirable in the following situations.

// MyForm.cs. Your code goes into this class

public partial class MyForm : Form
{
    public MyForm()
    {
        InitializeComponent();
    }

    // Your code would be added here ...
}

// MyForm.Designer.cs. Automatically generated code maintained by VS.NET as you add/remove controls

partial class MyForm
{
    private System.ComponentModel.IContainer components = null;

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code
    ...
    #endregion
}

Note the following points about the partial keyword:

public class MyClass
{
    partial class MyPartialClass
    {
        ...
    }

    ...

    partial class MyPartialClass
    {
        ...
    }
}

[Synchronized]
public partial class MyClass { ... }

[Serializable]
public partial class MyClass { ... }

// Above two code fragments are equivalent to
[Synchronized]
[Serializable]
public partial class MyClass { ... }

public partial class Car : IEngine, IBody
{ ... }

public partial class Car : Vehicle
{ ... }

// Above two code fragments are equivalent to
public partial class Car : Vehicle, IEnging, IBody
{ ... }

readonly

Applies To: fields

readonly is a modifier that can only be applied to class fields. A readonly field cannot be assigned a value during program execution except as part of its declaration or in a constructor of the same class.  See readonly in Classes section for a full example.

sealed

Applies To: class methods, indexers, properties, and events

A sealed class is one that cannot be inherited. It is typically used to prevent accidental inheritance of the class. struct are implicitly sealed and thus cannot be inherited. See Sealed Classes in Classes section.

static

Applies To: classes (new in C# 2.0), fields, methods, properties, events, operators, and constructors.

A static type or class member belongs to the class itself rather than to a specific object. Therefore, there is exactly only one copy of each static field in a class. Note the following:

unsafe

Applies To: Any callable class member (methods, indexer, property, constructor and so on - but not for static constructors)

The unsafe keyword is required for any block of code that uses pointers. Note that the scope of the unsafe keyword extends from the parameter list to the end of the class member. For example:

unsafe public void Square( int *pN )
{
    *pN = (*pN) * (*pN);
}

To compile .NET code that contains an unsafe code you must use the /unsafe compiler option. See Unsafe chapter for more details.

virtual

Applies To: methods, properties, events, and indexers.

The virtual keyword is used to indicate that the implementation of the affected class member depends on the runtime-type of the object being invoked. So when a virtual method is invoked, the runtime-type of the invoked object is checked for an overriding member. The overriding member in the most-derived class is then called.

Note the following points:

See Virtual Methods in Classes section

volatile

Applies To: fields.

The volatile keyword indicates that a filed can be modified in the program by the operating system, hardware, or another concurrently executing thread. A volatile field is usually used for fields that will be accessed by multiple threads without using the lock statement to synchronize access. Using the volatile modifier ensures that one thread retrieves the most-up-to-date value written by another field.

See Volatile fields in Classes section.