Introduction to a C# Class
Figure 3-1 displays a
class declaration followed by a body containing typical class members: a
constant, fields, a constructor containing initialization code, a property, and
a method. Its purpose is to familiarize you with the syntax common to most C#
classes and serve as a reference for later examples.
Defining
a Class
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.
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.
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.
![]() |
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.
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"); }
}
#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.
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
![]() |
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.
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).
//
.. 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.
Overview of Class Members
Table 3-1 provides a
summary of the types that comprise a .NET class. They can be classified broadly
as members that hold data—constants, fields, and properties—and members that
provide functionality—the constructor, method, and event. We'll look at each
individually.
Member Type
|
Valid In
|
Description
|
---|---|---|
Constant
|
Class, Structure
|
A symbol that represents an unchanging value. The compiler
associates it with the class—not an instance of the class.
|
Field
|
Class, Structure
|
A variable that holds a data value. It may be read-only or
read/write.
|
Property
|
Class, Structure
|
Provides access to a value in a class. It uses an accessor that specifies the code to be executed in
order to read or write the value. The code to read or write to a property is
implemented implicitly by .NET as two separate methods.
|
Constructor
|
Class, Structure
|
C# has three types of constructors:
|
Method
|
Class, Structure, Interface
|
A function associated with the class that defines an action or
computation.
|
Events
|
Class, Structure, Interface
|
A way for a class or object to notify other classes or objects
that its state has changed.
|
Types
|
Class, Structure, Interface
|
Classes, interfaces, structs,
delegates.
|
Member Access Modifiers
The access modifiers used for a class declaration can also be
applied to class members. They determine the classes and assemblies that have
access to the class. Table 3-2
summarizes the scope of accessibility.
Access Modifiers
| ||||
---|---|---|---|---|
Class can be accessed by classes
in:
|
Public
|
protected
|
Internal
|
private
|
Another assembly
|
Yes
|
No
|
||
Same assembly
|
Yes
|
Yes
|
||
Containing class
|
Yes
|
Yes
|
Yes
|
Yes
|
Class derived from containing class
|
Yes
|
Yes
|
Yes
|
No
|
No comments:
Post a Comment
Comment Here