In this article, I’ll begin exploring C# classes, the most common way to define a new reference type.

A class declaration in C# is composed of attributes, modifiers, the class name, bases, and a body. Attributes, modifiers, and bases are all optional. The body contains class members that can include constants, fields (or variables), methods, properties, indexers, events, operators, and nested types. Nested types are defined by class, interface, delegate, struct, or enum declarations within the class body. In C++, developers often place the class declaration in a .h file and place method implementations in one or more .cpp files that #include that .h file. C# doesn’t support this practice. With one exception, which I’ll cover later, C# method implementations are within the class body, in the same file.

Attributes allow you to add custom information to the metadata for a class. Metadata is analogous to a COM type library. It contains information about a class such as its name, its fields, and its methods, including their parameters and types. Metadata is essential to enable the .NET run time to load and use a class. The .NET run time reads the metadata through a process known as reflection. You can use reflection to access your own custom class metadata. I’ll discuss attributes and metadata in a future article.

Modifiers allow you to control access to the class and to restrict the ability of the class to be instantiated or to serve as the base of another class. The class modifiers are public, protected, internal, private, abstract, sealed, and new. Using these attributes, the following access levels can be specified:

  • public—Access is unrestricted.
  • protected—Access is restricted to the containing class or to classes derived from it.
  • internal—Access is restricted to the containing assembly (program).
  • protected internal—Allow protected or internal access. You can also specify this access level as internalprotected.
  • private—Access is restricted to the containing class.

A class that is not nested within another class may specify only public or internal access, while a nested class or other class member may specify any of the five access levels. If the modifiers are omitted, access defaults to internal for nonnested classes and private for nested classes and other class members. C++ doesn’t have this notion of explicit access control for nonnested classes. Instead, compiler-specific extensions or packaging mechanisms outside the C++ language can be used to achieve similar results. For example, Microsoft Visual C++ provides the __declspec(dllexport) extended storage class attribute, which you can apply to a class packaged within a DLL to make it available to external clients.

The term assembly may be new to C++ or Visual Basic programmers. An assembly is a self-describing collection of types and resources. Each assembly contains metadata, known as the manifest, which lists the types in the assembly and any dependencies it has on types in other assemblies. Further, the manifest specifies which of its types and resources are exposed outside the assembly. Although typically stored in a file with a .dll or .exe extension, an assembly is really more of a logical DLL because it can be composed of multiple files. The manifest lists all of the files included in the assembly. The manifest for a multiple-file assembly may be either standalone or be included in one of the assembly files.

The abstract modifier indicates that a class is incomplete and must be extended by a derived class in order to be instantiated. Conversely, a sealed class cannot be extended—it cannot serve as the base for another class. These attributes are useful in frameworks to ensure that classes are used as intended. In addition, the sealed attribute enables virtual class methods to be optimized at run time since it isn’t necessary to allow for method overriding in derived classes. The abstract and sealed attributes are mutually exclusive.

The new modifier may be applied only to a nested class or other class member, to indicate that it hides an inherited member of the same name. Hiding isn’t necessarily an error, but the compiler will issue a warning. You can attach the new modifier to the nested class to tell the compiler that you’re aware of the situation and that everything is okay. This will suppress the warning.

Class bases
A class may specify a single base class. C# does not support multiple inheritance. A derived class inherits all members from the base class except for constructors and destructors. However, the derived class may not have access to all of the inherited members, depending upon their access level. The base class defaults to the built-in class object if you do not specify one. In C#, object is the only class that does not have a base class. A base class must be at least as accessible as the derived class. For example, a public class cannot specify an internal class as its base. Finally, a class may not specify a base class that is one of the .NET framework classes used by C# to implement its own types. These classes include System.Array, System.Delegate, System.Enum, and System.ValueType.

In addition to deriving from a base class, a class may also implement interfaces. An interface provides specification but no implementation. An interface may specify methods, properties, events, and indexers. The interface members have implicit public access. A class implements an interface by supplying an implementation for each interface member. A class may implement multiple interfaces. Any interfaces that a class implements are listed after the base class, if any.

With this background, let’s take a look at the example below. Class A implicitly derives from object. Class B derives from A and implements interface IFoo. B also contains the program entry point, Main. Both A and B have public access. No attributes are specified.
using System;
interface IFoo
  void DoFoo();
public class A
  public int Increment( int x )
    return ++x;
public class B : A, IFoo
  // Implement IFoo methods.
  public void DoFoo()
    // Call the Increment method inherited from A.
    Console.WriteLine( “B.DoFoo: {0}”, Increment( 41 ) );
  static void Main()
    B b = new B();
B.DoFoo: 42


We’ve just covered the basics of creating classes and examined a few characteristics that are new to C#. In the next article, I’ll continue our C# type discussion with a look at class members.

What do you think about C#?

What are your plans for switching to C#? What C# features are the most appealing to you? Send us an e-mail with your thoughts and experiences or post a comment below.