楼主: bnso

Introduction to C# Programming

[复制链接]
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
111#
 楼主| 发表于 2006-8-13 21:37 | 只看该作者
10 Module 9: Creating and Destroying Objects
Initializing an Object in More Than One Way
The ability to initialize an object in different ways was one of the primary
motivations for allowing overloading. Constructors are special kinds of
methods, and they can be overloaded exactly like methods. This means you can
define different ways to initialize an object. The following code provides an
example:
class Overload
{
private int data;
public Overload( ) { this.data = -1; }
public Overload(int x) { this.data = x; }
}
class Use
{
static void Main( )
{
Overload o1 = new Overload( );
Overload o2 = new Overload(42);
...
}
}
Object o1 is created by using the constructor that takes no arguments, and the
private instance variable data is set to –1. Object o2 is created by using the
constructor that takes a single integer, and the instance variable data is set to 42.
Initializing Fields to Non-Default Values
You will find many cases in which fields cannot be sensibly initialized to zero.
In these cases, you can write your own constructor that requires one or more
parameters that are then used to initialize the fields. For example, consider the
following Date class:
class Date
{
public Date(int year, int month, int day)
{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
}
One problem with this constructor is that it is easy to get the order of the
arguments wrong. For example:
Date birthday = new Date(23, 11, 1968); // Error
Module 9: Creating and Destroying Objects 11
The code should read new Date(1968,11,23). This error will not be
detected as a compile-time error because all three arguments are integers. One
way you could fix this would be to use the Whole Value pattern. You could turn
Year, Month, and Day into structs rather than int values, as follows:
struct Year
{
public readonly int value;
public Year(int value) { this.value = value; }
}
struct Month // Or as an enum
{
public readonly int value;
public Month(int value) { this.value = value; }
}
struct Day
{
public readonly int value;
public Day(int value) { this.value = value; }
}
class Date
{
public Date(Year y, Month m, Day d)
{
ccyy = y.value;
mm = m.value;
dd = d.value;
}
private int ccyy, mm, dd;
}
Using structs or enums rather than classes for Day, Month, and Year
reduces the overhead when creating a Date object. This will be explained later
in this module.
The following code shows a simple change that would not only catch argumentorder
errors but would also allow you to create overloaded Date constructors
for U.K. format, U.S. format, and ISO format:
class Date
{
public Date(Year y, Month m, Day d) { ... } // ISO
public Date(Month m, Day d, Year y) { ... } // US
public Date(Day d, Month m, Year y) { ... } // UK
...
private int ccyy, mm, dd;
}
Tip
12 Module 9: Creating and Destroying Objects
Overloading and the Default Constructor
If you declare a class with a constructor, the compiler does not generate the
default constructor. In the following example, the Date class is declared with a
constructor, so the expression new Date( ) will not compile:
class Date
{
public Date(Year y, Month m, Day d) { ... }
// No other constructor
private int ccyy, mm, dd;
}
class Fails
{
static void Main( )
{
Date defaulted = new Date( ); // Compile -time error
}
}
This means that if you want to be able to create Date objects without supplying
any constructor arguments, you will need to explicitly declare an overloaded
default constructor, as in the following example:
class Date
{
public Date( ) { ... }
public Date(Year y, Month m, Day d) { ... }
...
private int ccyy, mm, dd;
}
class Succeeds
{
static void Main( )
{
Date defaulted = new Date( ); // Okay
}
}

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
112#
 楼主| 发表于 2006-8-13 21:37 | 只看该作者
Module 9: Creating and Destroying Objects 13
u Initializing Data
n Using Initializer Lists
n Declaring Readonly Variables and Constants
n Initializing Readonly Fields
n Declaring a Constructor for a Struct
n Using Private Constructors
n Using Static Constructors
You have seen the basic elements of constructors. Constructors also have a
number of additional features and uses. In this section you will learn how to
initialize the data in objects by using constructors.
14 Module 9: Creating and Destroying Objects
Using Initializer Lists
n Overloaded Constructors Might Contain Duplicate Code
l Refactor by making constructors call each other
l Use the this keyword in an initializer list
class Date
{
...
public Date( ) : this(1970, 1, 1) { }
public Date(int year, int month, int day) { ... }
}
class Date
{
...
public Date( ) : this(1970, 1, 1) { }
public Date(int year, int month, int day) { ... }
}
You can use special syntax called an initializer list to implement one
constructor by calling an overloaded constructor.
Avoiding Duplicate Initia lizations
The following code shows an example of overloaded constructors with
duplicated initialization code:
class Date
{
public Date( )
{
ccyy = 1970;
mm = 1;
dd = 1;
}
public Date(int year, int month, int day)
{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
}
Notice the duplication of dd, mm, and ccyy on the left side of the three
initializations. This is not extensive duplication, but it is duplication nonetheless,
and you should avoid it if possible. For example, suppose you decided to
change the representation of a Date to one long field. You would need to
rewrite every Date constructor.
Module 9: Creating and Destroying Objects 15
Refactoring Duplicate Initializations
A standard way to refactor duplic ate code is to extract the common code into its
own method. The following code provides an example:
class Date
{
public Date( )
{
Init(1970, 1, 1);
}
public Date(int year, int month, int day)
{
Init(day, month, year);
}
private void Init(int year, int month, int day)
{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
}
This is better than the previous solution. Now if you changed the representation
of a Date to one long field, you would only need to modify Init. Unfortunately,
refactoring constructors in this way works some of the time but not all of the
time. For example, it will not work if you try to refactor the initialization of a
readonly field. (This is covered later in this module.) Object-oriented
programming languages provide mechanisms to help solve this known problem.
For example, in C++ you can use default values. In C# you use initializer lists.
Using an Initializer List
An initializer list allows you to write a constructor that calls another constructor
in the same class. You write the initializer list between the closing parenthesis
mark and the opening left brace of the constructor. An initializer list starts with
a colon and is followed by the keyword this and then any arguments between
parentheses. For example, in the following code, the default Date constructor
(the one with no arguments) uses an initializer list to call the second Date
constructor with three arguments: 1970, 1, and 1.
class Date
{
public Date( ) : this(1970, 1, 1)
{
}
public Date(int year, int month, int day)
{
ccyy = year;
mm = month;
dd = day;
}
private int ccyy, mm, dd;
}
This syntax is efficient, it always works, and if you use it you do not need to
create an extra Init method.
16 Module 9: Creating and Destroying Objects
Initializer List Restrictions
There are three restrictions you must observe when initializing constructors:
n You can only use initializer lists in constructors as shown in the following
example:
class Point
{
public Point(int x, int y) { ... }
// Compile-time error
public void Init( ) : this(0, 0) { }
}
n You cannot write an initializer list that calls itself. The following code
provides an example:
class Point
{
// Compile-time error
public Point(int x, int y) : this(x, y) { }
}
n You cannot use the this keyword in an expression to create a constructor
argument. The following code provides an example:
class Point
{
// Compile-time error
public Point( ) : this(X(this), Y(this)) { }
public Point(int x, int y) { ... }
private static int X(Point p) { ... }
private static int Y(Point p) { ... }
}

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
113#
 楼主| 发表于 2006-8-13 21:38 | 只看该作者
Module 9: Creating and Destroying Objects 17
Declaring Readonly Variables and Constants
n Value of Constant Field
Is Obtained at Compile
Time
n Value of Readonly
Field Is Obtained at
Run Time
When using constructors, you need to know how to declare readonly variables
and constants.
Using Readonly Variables
You can qualify a field as readonly in its declaration, as follows:
readonly int nLoopCount = 10;
You will get an error if you attempt to change the value at run time.
Using Constant Variables
A constant variable represents a constant value that is computed at compile time.
Using constant variables, you can define variables whose values never change,
as shown in the following example:
const int speedLimit = 55;
Constants can depend on other constants within the same program as long as
the dependencies are not of a circular nature. The compiler automatically
evaluates the constant declarations in the appropriate order.
18 Module 9: Creating and Destroying Objects
Initializing Readonly Fields
n Readonly Fields Must Be Initialized
l Implicitly to zero, false or null
l Explicitly at their declaration in a variable initializer
l Explicitly inside an instance constructor
class SourceFile
{
private readonly ArrayList lines;
}
class SourceFile
{
private readonly ArrayList lines;
}
Fields that cannot be reassigned and that must be initialized are called readonly
fields. There are three ways to initialize a readonly field:
n Use the default initialization of a readonly field.
n Initialize a readonly field in a constructor.
n Initialize readonly fields by using a variable initializer.
Using the Default Initialization of a Readonly Field
The compiler-generated default constructor will initialize all fields (whether
they are readonly or not) to their default value of zero, false, or null. The
following code provides an example:
class SourceFile
{
public readonly ArrayList lines;
}
class Test
{
static void Main( )
{
SourceFile src = new SourceFile( );
Console.WriteLine(src.lines == null); // True
}
}
There is no SourceFile constructor, so the compiler writes a default constructor
for you, which will initialize lines to null. Hence the WriteLine statement in
the preceding example writes "True.”

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
114#
 楼主| 发表于 2006-8-13 21:38 | 只看该作者
Module 9: Creating and Destroying Objects 19
If you declare your own constructor in a class and do not explicitly initialize a
readonly field, the compiler will still automatically initialize the field.
Following is an example:
class SourceFile
{
public SourceFile( ) { }
public readonly ArrayList lines;
}
class Test
{
static void Main( )
{
SourceFile src = new SourceFile( );
Console.WriteLine(src.lines == null); // Still true
}
}
This is not very useful. In this case, the readonly field is initialized to null, and
it will remain null because you cannot reassign a readonly field.
Initializing a Readonly Field in a Constructor
You can explicitly initialize a readonly field in the body of a constructor.
Following is an example:
class SourceFile
{
public SourceFile( )
{
lines = new ArrayList( );
}
private readonly ArrayList lines;
}
The statement inside the constructor looks syntactically like an assignment to
lines, which would not normally be allowed because lines is a readonly field.
However, the statement compiles because the compiler recognizes that the
assignment occurs inside a constructor body and so treats it as an initialization.
An advantage of initializing readonly fields like this is that you can use
constructor parameters in the new expression. Following is an example:
class SourceFile
{
public SourceFile(int suggestedSize )
{
lines = new ArrayList(suggestedSize);
}
private readonly ArrayList lines;
}
20 Module 9: Creating and Destroying Objects
Initializing Readonly Fields Using a Variable Initializer
You can initialize a readonly field directly at its declaration by using a variable
initializer. Following is an example:
class SourceFile
{
public SourceFile( )
{
...
}
private readonly ArrayList lines = new ArrayList( );
}
This is really just convenient shorthand. The compiler conceptually rewrites a
variable initialization (whether it is readonly or not) into an assignment inside
all constructors. For example, the preceding class will conceptually be
converted into the following class:
class SourceFile
{
public SourceFile( )
{
lines = new ArrayList( );
...
}
private readonly ArrayList lines;
}

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
115#
 楼主| 发表于 2006-8-13 21:38 | 只看该作者
Module 9: Creating and Destroying Objects 21
Declaring a Constructor for a Struct
n The Compiler
l Always generates a default constructor. Default
constructors automatically initialize all fields to zero.
n The Programmer
l Can declare constructors with one or more arguments.
Declared constructors do not automatically initialize
fields to zero.
l Can never declare a default constructor.
l Can never declare a protected constructor.
The syntax you use to declare a constructor is the same for a struct as it is for a
class. For example, the following is a struct called Point that has a constructor:
struct Point
{
public Point(int x, int y) { ... }
...
}
Struct Constructor Restrictions
Although the syntax for struct and class constructors is the same, there are some
additional restrictions that apply to struct constructors:
n The compiler always creates a default struct constructor.
n You cannot declare a default constructor in a struct.
n You cannot declare a protected constructor in a struct.
n You must initialize all fields.
22 Module 9: Creating and Destroying Objects
The Compiler Always Creates a Default Struct Constructor
The compiler always generates a default constructor, regardless of whether you
declare constructors yourself. (This is unlike the situation with classes, in which
the compiler-generated default constructor is only generated if you do not
declare any constructors yourself.) The compiler generated struct constructor
initializes all fie lds to zero, false, or null.
struct SPoint
{
public SPoint(int x, int y) { ... }
...
static void Main( )
{
// Okay
SPoint p = new SPoint( );
}
}
class CPoint
{
public CPoint(int x, int y) { ... }
...
static void Main( )
{
// Compile-time error
CPoint p = new CPoint( );
}
}
This means that a struct value created with
SPoint p = new SPoint( );
creates a new struct value on the stack (using new to create a struct does not
acquire memory from the heap) and initializes the fields to zero. There is no
way to change this behavior.
However, a struct value created with
SPoint p;
Module 9: Creating and Destroying Objects 23
still creates a struct value on the stack but does not initialize any of the fields
(so any field must be definitely assigned before it can be referenced). Following
is an example:
struct SPoint
{
public int x, y;
...
static void Main( )
{
SPoint p1;
Console.WriteLine(p1.x); // Compile-time error
SPoint p2;
p2.x = 0;
Console.WriteLine(p2.x); // Okay
}
}
Ensure that any struct type that you define is valid with all fields set to
zero.
You Cannot Declare a Default Constructor in a Struct
The reason for this restriction is that the compiler always creates a default
constructor in a struct (as just described) so you would end up with a duplicate
definition.
class CPoint
{
// Okay because CPoint is a class
public CPoint( ) { ... }
...
}
struct SPoint
{
// Compile-time error because SPoint is a struct
public SPoint( ) { ... }
...
}
You can declare a struct constructor as long as it expects at least one argument.
If you declare a struct constructor it will not automatically initialize any field to
a default value (unlike the compiler generated struct default constructor which
will).
struct SPoint
{
public SPoint(int x, int y) { ... }
...
}
Tip

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
116#
 楼主| 发表于 2006-8-13 21:38 | 只看该作者
24 Module 9: Creating and Destroying Objects
You Cannot Declare a Protected Constructor in a Struct
The reason for this restriction is that you can never derive other classes or
structs from a struct, and so protected access would not make sense, as shown
in the following example:
class CPoint
{
// Okay
protected CPoint(int x, int y) { ... }
}
struct SPoint
{
// Compile-time error
protected SPoint(int x, int y) { .. . }
}
You Must Initialize All Fields
If you declare a class constructor that fails to initialize a field, the compiler will
ensure that the field nevertheless retains its default zero initialization. The
following code provides an example:
class CPoint
{
private int x, y;
public CPoint(int x, int y) { /*nothing*/ }
// Okay. Compiler ensures that x and y are initialized to
// zero.
}
However, if you declare a struct constructor that fails to initialize a field, the
compiler will generate a compile-time error:
struct SPoint1 // Okay: initialized when declared
{
private int x = 0, y = 0;
public SPoint1(int x, int y) { }
}
struct SPoint2 // Okay: initialized in constructor
{
private int x, y;
public SPoint2(int x, int y)
{
this.x = x;
this.y = y;
}
}
struct SPoint3 // Compile-time error
{
private int x, y;
public SPoint3(int x, int y) { }
}
Module 9: Creating and Destroying Objects 25
Using Private Constructors
n A Private Constructor Prevents Unwanted Objects from
Being Created
l Instance methods cannot be called
l Static methods can be called
l A useful way of implementing procedural functions
public class Math
{
public static double Cos(double x) { ... }
public static double Sin(double x) { ... }
private Math( ) { }
}
public class Math
{
public static double Cos(double x) { ... }
public static double Sin(double x) { ... }
private Math( ) { }
}
Math is part of the .NET SDK
So far, you have learned how to use public constructors. C# also provides
private constructors, which are useful in some applications.
Using Private Constructors for Procedural Functions
Object-oriented programming offers a powerful paradigm for structuring
software in many diverse domains. However, it is not a universally applicable
paradigm. For example, there is nothing object oriented about calculating the
sine or cosine of a double-precision floating-point number.
Declaring Functions
The most intuitive way to calculate a sine or cosine is to use global functions
defined outside an object, as follows:
double Cos(double x) { ... }
double Sin(double x) { ... }
The preceding code is not allowable in C#. Global functions are possible in
procedural languages such as C and in hybrid languages such as C++, but they
are not allowed in C#. In C#, functions must be declared inside a class or struct,
as follows:
class Math
{
public double Cos(double x) { ... }
public double Sin(double x) { ... }
}

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
117#
 楼主| 发表于 2006-8-13 21:39 | 只看该作者
26 Module 9: Creating and Destroying Objects
Declaring Static vs. Instance Methods
The problem with the technique in the preceding example is that, because Cos
and Sin are instance methods, you are forced to create a Math object from
which to invoke Sin or Cos , as shown in the following code:
class Cumbersome
{
static void Main( )
{
Math m = new Math( );
double answer;
answer = m.Cos(42.0);
// Or
answer = new Math( ).Cos(42.0);
}
}
However, you can easily solve this by declaring Cos and Sin as static methods,
as follows:
class Math
{
public static double Cos(double x) { ... }
public static double Sin(double x) { ... }
}
class LessCumbersome
{
static void Main( )
{
double answer = Math.Cos(42.0);
}
}
Module 9: Creating and Destroying Objects 27
Benefits of Static Methods
If you declare Cos as a static method, the syntax for using Cos becomes:
n Simpler
You have only one way to call Cos (by means of Math), whereas in the
previous example you had two ways (by means of m and by means of new
Math( )).
n Faster
You no longer need to create a new Math object.
One slight problem remains. The compiler will generate a default constructor
with public access, allowing you to create Math objects. Such objects can serve
no purpose because the Math class contains static methods only. There are two
ways you can prevent Math objects from being created:
n Declare Math as an abstract class.
This is not a good idea. The purpose of abstract classes is to be derived from.
n Declare a private Math constructor.
This is a better solution. When you declare a constructor in the Math class,
you prevent the compiler from generating the default constructor, and if you
also declare the constructor as private, you stop Math objects from being
created. The private constructor also prevents Math from being used as a
base class.
The Singleton Pattern
The intent of the Singleton pattern (which is discussed in Design Patterns:
Elements of Reusable Object-Oriented Software) is to “ensure a class only has
one instance, and provide a global point of access to it.” The technique of
declaring a class by using a private constructor and static methods is sometimes
suggested as a way to implement the Singleton pattern.
A key aspect of the Singleton pattern is that a class has a single instance.
With a private constructor and static methods, there is no instance at all. The
canonical implementation of the Singleton pattern is to create a static method
that gives access to the single instance, and this instance is then used to call
instance methods.
Note

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
118#
 楼主| 发表于 2006-8-13 21:39 | 只看该作者
28 Module 9: Creating and Destroying Objects
Using Static Constructors
n Purpose
l Called by the class loader at run time
l Can be used to initialize static fields
l Guaranteed to be called before instance constructor
n Restrictions
l Cannot be called
l Cannot have an access modifier
l Must be parameterless
Just as an instance constructor guarantees that an object is in a well-defined
initial state before it is used, a static constructor guarantees that a class is in a
well-defined initial state before it is used.
Loading Classes at Run Time
C# is a dynamic language. When the Common Language Runtime is running a
Microsoft? .NET program, it often encounters code that uses a class that has not
yet been loaded. In these situations, execution is momentarily suspended, the
class is dynamically loaded, and then execution continues.
Initializing Classes at Load Time
C# ensures that a class is always initialized before it is used in code in any way.
This guarantee is achieved by using static constructors.
You can declare a static constructor like an instance constructor but prefix it
with the keyword static, as follows:
class Example
{
static Example( ) { ... }
}
Module 9: Creating and Destroying Objects 29
After the class loader loads a class that will soon be used, but before it
continues normal execution, it executes the static constructor for that class.
Because of this process, you are guaranteed that classes are always initialized
before they are used. The specific guarantees that the class loader provides are
as follows:
n The static constructor for a class is executed before any instances of the
class are created.
n The static constructor for a class is executed before any static member of the
class is referenced.
n The static constructor for a class is executed before the static constructor of
any of its derived classes is executed.
n The static constructor for a class never executes more than once.
Static Field Initializations and Static Constructors
The most common use for a static constructor is to initialize the static fields of a
class. This is because when you initialize a static field directly at its point of
declaration, the compiler conceptually converts the initialization into an
assignment inside the static constructor. In other words
class Example
{
private static Wibble w = new Wibble( );
}
is effectively converted by the compiler into
class Example
{
static Example( )
{
w = new Wibble( );
}
private static Wibble w;
}
Static Constructor Restrictions
Understanding the following four restrictions on the syntax of static
constructors will help you understand how the Common Language Runtime
uses static constructors:
n You cannot call a static constructor.
n You cannot declare a static constructor with an access modifier.
n You cannot declare a static constructor with parameters.
n You cannot use the this keyword in a static constructor.
30 Module 9: Creating and Destroying Objects
You Cannot Call a Static Constructor
A static constructor must be called before any instances of the class are
referenced in code. If the responsibility for enforcing this rule were given to
programmers rather than the .NET runtime, eventually programmers would fail
to meet the responsibility. They would forget to make the call, or, perhaps
worse, they would call the static constructor more than once. The .NET runtime
avoids these potential problems by disallowing calls to static constructors in
code. Only the .NET runtime can call a static constructor.
class Point
{
static Point( ) { ... }
static void Main( )
{
Point.Point( ); // Compile-time error
}
}
You Cannot Declare a Static Constructor with an Access Modifier
Because you cannot call a static constructor, declaring a static constructor with
an access modifier does not make sense and causes a compile -time error:
class Point
{
public static Point( ) { ... } // Compile-time error
}
You Cannot Declare a Static Constructor with Parameters
Because you cannot call a static constructor, declaring a static constructor with
parameters does not make sense and causes a compile-time error. This also
means that you cannot declare overloaded static constructors. Following is an
example:
class Point
{
static Point(int x ) { ... } // Compile-time error
}
You Cannot Use the this Keyword in a Static Constructor
Because a static constructor initializes the class and not object instances, it does
not have an implicit this reference, so any attempt to use the this keyword
results in a compile-time error:
class Point
{
private int x, y;
static Point( ) : this (0,0) // Compile-time error
{
this.x = 0; // Compile-time error
this.y = 0; // Compile-time error
}
...
}

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
119#
 楼主| 发表于 2006-8-13 21:40 | 只看该作者
Module 9: Creating and Destroying Objects 31
Lab 9.1: Creating Objects
Objectives
In this lab, you will modify the BankAccount class that you created in the
previous labs so that it uses constructors. You will also create a new class,
BankTransaction, and use it to store information about the transactions
(deposits and withdrawals) performed on an account.
After completing this lab, you will be able to:
n Override the default constructor.
n Create overloaded constructors.
n Initialize readonly data.
Prerequisites
Before working on this lab, you must be able to:
n Create classes and instantiate objects.
n Define and call methods.
You should also have completed Lab 8. If you did not complete Lab 8, you can
use the solution code provided.
Estimated time to complete this lab: 60 minutes
32 Module 9: Creating and Destroying Objects
Exercise 1
Implementing Constructors
In this exercise, you will modify the BankAccount class that you created in the
previous labs. You will remove the methods that populate the account number
and account type instance variables and replace them with a series of
constructors that can be used when a BankAccount is instantiated.
You will overrid e the default constructor to generate an account number (by
using the technique that you used earlier), set the account type to Checking,
and set the balance to zero.
You will also create three more constructors that take different combinations of
parameters:
n The first will take an AccountType . The constructor will generate an
account number, set the balance to zero, and set the account type to the
value passed in.
n The second will take a decimal. The constructor will generate an account
number, set the account type to Checking, and set the balance to the value
passed in.
n The third will take an AccountType and a decimal. The constructor will
generate an account number, set the account type to the value of the
AccountType parameter, and set the balance to the value of the decimal
parameter.
? To create the default constructor
1. Open the Constructors.sln project in the Lab Files\
Lab09\Starter\Constructors folder.
2. In the BankAccount class, delete the Populate method.
3. Create a default constructor, as follows:
a. The name is BankAccount.
b. It is public.
c. It takes no parameters.
d. It has no return type.
e. The body of the constructor should generate an account number by using
the NextNumber method, set the account type to
AccountType.Checking, and initialize the account balance to zero.
The completed constructor is as follows:
public BankAccount( )
{
accNo = NextNumber( );
accType = AccountType.Checking;
accBal = 0;
}
Module 9: Creating and Destroying Objects 33
? To create the remaining constructors
1. Add another constructor that takes a single AccountType parameter called
aType . The constructor should:
a. Generate an account number as before.
b. Set accType to aType.
c. Set accBal to zero.
2. Define another constructor that takes a single decimal parameter called
aBal. The constructor should:
a. Generate an account number.
b. Set accType to AccountType.Checking.
c. Set accBal to aBal.
3. Define a final constructor that takes two parameters: an AccountType
called aType and a decimal called aBal. The constructor should:
a. Generate an account number.
b. Set accType to aType.
c. Set accBal to aBal.
The completed code for all three constructors is as follows:
public BankAccount(AccountType aType)
{
accNo = NextNumber( );
accType = aType;
accBal = 0;
}
public BankAccount(decimal aBal)
{
accNo = NextNumber( );
accType = AccountType.Checking;
accBal = aBal;
}
public BankAccount(AccountType aType, decimal aBal)
{
accNo = NextNumber( );
accType = aType;
accBal = aBal;
}

使用道具 举报

回复
论坛徽章:
49
NBA季后赛之星
日期:2014-10-19 19:51:33蓝锆石
日期:2014-10-19 19:51:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33指数菠菜纪念章
日期:2014-10-19 19:52:33问答徽章
日期:2014-04-15 10:41:44优秀写手
日期:2014-07-24 06:00:11保时捷
日期:2014-10-19 19:51:33三菱
日期:2014-10-19 19:51:33
120#
 楼主| 发表于 2006-8-13 21:40 | 只看该作者
34 Module 9: Creating and Destroying Objects
? To test the constructors
1. In the Main method of the CreateAccount class, define four BankAccount
variables called acc1, acc2, acc3, and acc4.
2. Instantiate acc1 by using the default constructor.
3. Instantiate acc2 by using the constructor that takes only an AccountType .
Set the type of acc2 to AccountType.Deposit.
4. Instantiate acc3 by using the constructor that takes only a decimal balance.
Set the balance of acc3 to 100.
5. Instantiate acc4 by using the constructor that takes an AccountType and a
decimal balance. Set the type of acc4 to AccountType.Deposit, and set the
balance to 500.
6. Use the Write method (supplied with the CreateAccount class) to display
the contents of each account one by one. The completed code is as follows:
static void Main( )
{
BankAccount acc1, acc2, acc3, acc4;
acc1 = new BankAccount( );
acc2 = new BankAccount(AccountType.Deposit);
acc3 = new BankAccount(100);
acc4 = new BankAccount(AccountType.Deposit, 500);
Write(acc1);
Write(acc2);
Write(acc3);
Write(acc4);
}
7. Compile the project and correct any errors. Execute it, and check that the
output is as expected.
Module 9: Creating and Destroying Objects 35
Exercise 2
Initializing readonly Data
In this exercise, you will create a new class called BankTransaction. It will
hold information about a deposit or withdrawal transaction that is performed on
an account.
Whenever the balance of an account is changed by means of the Deposit or
Withdraw method, a new BankTransaction object will be created. The
BankTransaction object will contain the current date and time (generated from
System.DateTime) and the amount added (positive) or deducted (negative)
from the account. Because transaction data cannot be changed once it is created,
this information will be stored in two readonly instance variables in the
BankTransaction object.
The constructor for BankTransaction will take a single decimal parameter,
which it will use to populate the transaction amount instance variable. The date
and time instance variable will be populated by DateTime.Now, a property of
System.DateTime that returns the current date and time.
You will modify the BankAccount class to create transactions in the Deposit
and Withdraw methods. You will store the transactions in an instance variable
in the BankAccount class of type System.Collections.Queue. A queue is a
data structure that holds an ordered list of objects. It provides methods for
adding elements to the queue and for iterating through the queue. (Using a
queue is better than using an array because a queue does not have a fixed size: it
will grow automatically as more transactions are added.)
? To create the BankTransaction class
1. Open the Constructors.sln project in the Lab Files\
Lab09\Starter\Constructors folder, if it is not already open.
2. Add a new class called BankTransaction.
3. In the BankTransaction class, remove the namespace directive together
with the first opening brace ({), and the final closing brace (}). (You will
learn more about namespaces in a later module.)
4. In the summary comment, add a brief description of the BankTransaction
class. Use the description above to help you.
5. Delete the default constructor created by Visual Studio.
6. Add the following two private readonly instance variables:
a. A decimal called amount.
b. A DateTime variable called when. The System.DateTime structure is
useful for holding dates and times, and contains a number of methods for
manipulating these values.

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表