3.2. Defining a Class

 < Day Day Up > 

A class definition consists of an optional attributes list, optional modifiers, the word class followed by the class identifier (name), and an optional list containing a base class or interfaces to be used for inheritance. Following this class declaration is the class body, consisting of the code and class members such as methods and properties.

Syntax for class definition:

 [attributes] [modifiers] class  identifier [:baselist] {class body} [;] 

Classes as do all .NET types inherit from the System.Object class. This inheritance is implicit and is thus not specified as part of the class definition. As we'll see in the discussion of inheritance, this is important because a class can explicitly inherit from only one class.

Attributes

The optional attribute section consists of a pair of square brackets surrounding a comma-separated list of one or more attributes. An attribute consists of the attribute name followed by an optional list of positional or named arguments. The attribute may also contain an attribute target that is, the entity to which the attribute applies.

Examples

The attribute section contains an attribute name only:

 [ClassDesc] 

Single attribute with named argument and positional argument (0):

 [ClassDesc(Author="Knuth", 0)] 

Multiple attributes can be defined within brackets.:

 [ClassDesc(Author="Knuth"), ClassDesc(Author="James")] 

Description

Attributes provide a way to associate additional information with a target entity. In our discussion, the target is a newly created class; but attributes may also be associated with methods, fields, properties, parameters, structures, assemblies, and modules. Their simple definition belies a truly innovative and powerful programming tool. Consider the following:

  • An attribute is an instance of a public class. As such, it has fields and properties that can be used to provide rich descriptive information about a target or targets.

  • All compilers that target the Common Language Runtime (CLR) recognize attributes and store information about them in the module's metadata. This is an elegant way to attach information to a program entity that can affect its behavior without modifying its implementation code. An application can then use reflection (a set of types for reading metadata) to read the metadata at runtime and make decisions based on its value.

  • Hundreds of predefined attributes are included in the .NET Framework Class Library (FCL). They are used heavily in dealing with interoperability issues such as accessing the Win32API or allowing .NET applications and COM objects to communicate. They also are used to control compiler operations. The[assembly:CLSComplianttrue)] attribute in Figure 3-1 tells the C# compiler to check the code for CLS compliance.

Core Note

Attributes provide a way to extend the metadata generated by the C# compiler with custom descriptive information about a class or class member.


.NET supports two types of attributes: custom attributes and standard attributes. Custom attributes are defined by the programmer. The compiler adds them to the metadata, but it's up to the programmer to write the reflection code that incorporates this metadata into the program. Standard attributes are part of the .NET Framework and recognized by the runtime and .NET compilers. The Flags attribute that was discussed in conjunction with enums in Chapter 2, "C# Language Fundamentals," is an example of this; another is the conditional attribute, described next.

Conditional Attribute

The conditional attribute is attached to methods only. Its purpose is to indicate whether the compiler should generate Intermediate Language (IL) code to call the method. The compiler makes this determination by evaluating the symbol that is part of the attribute. If the symbol is defined (using the define preprocessor directive), code that contains calls to the method is included in the IL. Here is an example to demonstrate this:

File: attribs.cs (attribs.dll)

 #define DEBUG using System; using System.Diagnostics;   // Required for conditional attrib. public class AttributeTest {    [Conditional("TRACE")]    public static void ListTrace()    { Console.WriteLine("Trace is On"); }    [Conditional("DEBUG")]    public static void ListDebug()    { Console.WriteLine("Debug is On"); } } 

File: attribclient.cs (attribclient.exe)

 #define TRACE using System; public class MyApp {    static void Main()    {       Console.WriteLine("Testing Method Calls");       AttributeTest.ListTrace();       AttributeTest.ListDebug();    } } 

Executing attribclient yields the following output:

 Testing Method Calls Trace is On 

When attribclient is compiled, the compiler detects the existence of the trACE symbol, so the call to ListTrace is included. Because DEBUG is not defined, the call to ListDebug is excluded. The compiler ignores the fact that DEBUG is defined in attribs; its action is based on the symbols defined in the file containing the method calls. Note that a conditional attribute can be used only with methods having a return type of void.

Access Modifiers

The primary role of modifiers is to designate the accessibility (also called scope or visibility) of types and type members. Specifically, a class access modifier indicates whether a class is accessible from other assemblies, the same assembly, a containing class, or classes derived from a containing class.

public

A class can be accessed from any assembly.

protected

Applies only to a nested class (class defined within another class). Access is limited to the container class or classes derived from the container class.

internal

Access is limited to classes in the same assembly. This is the default access.

private

Applies only to a nested class. Access is limited to the container class.

protected internal

The only case where multiple modifiers may be used.

internal

Access is limited to the current assembly or types derived from the containing class.


Core Note

A base class must be at least as accessible as its derived class. The following raises an error:

 class  Furniture { }               // default access is internal public class Sofa : Furniture { }  // error 

The error occurs because the Furniture class (internal by default) is less accessible than the derived Sofa class. Errors such as this occur most frequently when a developer relies on a default modifer. This is one reason that modifiers should be included in a declaration.


Abstract, Sealed, and Static Modifiers

In addition to the access modifiers, C# provides a dozen or so other modifiers for use with types and type members. Of these, three can be used with classes: abstract, sealed, and static.

abstract

Indicates that a class is to be used only as a base class for other classes. This means that you cannot create an instance of the class directly. Any class derived from it must implement all of its abstract methods and accessors. Despite its name, an abstract class can possess nonabstract methods and properties.

sealed

Specifies that a class cannot be inherited (used as a base class). Note that .NET does not permit a class to be both abstract and sealed.

static

Specifies that a class contains only static members (.NET 2.0).


Class Identifier

This is the name assigned to the class. The ECMA standard recommends the following guidelines for naming the identifier:

  • Use a noun or noun phrase.

  • Use the Pascal case capitalization style: The first letter in the name and the first letter of each subsequent concatenated word are capitalized for example, BinaryTree.

  • Use abbreviations sparingly.

  • Do not use a type prefix, such as C, to designate all classes for example, BinaryTree, not CBinaryTree.

  • Do not use the underscore character.

  • By convention, interface names always begin with I; therefore, do not use I as the first character of a class name unless I is the first letter in an entire word for example, IntegralCalculator.

Base Classes, Interfaces, and Inheritance

This optional list contains a previously defined class or interface(s) from which a class may derive its behavior and capabilities. The new class is referred to as the derived class, and the class or interface from which it inherits is the base class or interface. A base class must be listed before any interface(s).

Example
 // .. FCL Interface and user-defined base class public interface System.Icomparable    {Int32 CompareTo(Object object); } class Furniture {  } // .. Derived Classes class Sofa: Furniture { ... }  // Inherits from one base class // Following inherits from one base class and one interface. class Recliner: Furniture, IComparable {...} 

The C# language does not permit multiple class inheritance, thus the base list can contain only one class. Because there is no limit on the number of inherited interfaces, this serves to increase the role of interfaces in the .NET world.

Core Note

  • Inheritance from a base class is referred to as implementation inheritance. The derived class inherits all of the members of the base class. However, the base class can prevent access to a member by defining it with the private modifier.

  • Inheritance from an interface is referred to as interface inheritance because the interface does not provide implementation code. The derived class must provide the logic to implement any functions defined in the base interface(s).


     < Day Day Up > 


    Core C# and  .NET
    Core C# and .NET
    ISBN: 131472275
    EAN: N/A
    Year: 2005
    Pages: 219

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net