第一章
Framework 基本原理
.NET Framework 是一个不可或缺的Microsoft Windows 组建,它被设计去支持下一代应用和服务。对于在其它面向对象环境下工作的开发者来说,许多.NET的原理都应该很熟悉;但是,.NET Framework 也包含许多特性,甚至对于最有经验的开发者来说都是最新的。这一章提供对.NET Framework 程序的概述。
使用.NET Framework去管理.NET Framework 应用中的数据
2.0 中的系统类型(参考System命名空间)
❑ Value types
❑ Reference types
❑ Attributes
❑ Generic types
❑ Exception classes
❑ Boxing and UnBoxing
❑ TypeForwardedToAttribute Class
■ .NET Interface,能使别的组建去遵守其规则。
标准接口. (参考System 命名空间)
❑ IComparable interface
❑ IDisposable interface
❑ IConvertible interface
❑ ICloneable interface
❑ IEquatable interface
❑ IFormattable interface
使用events和delegates去控制.NET 应用组建的互操作。
❑ Delegate class
❑ EventArgs class
❑ EventHandler delegates
第一课:使用值类型
.NET Framework 中最简单的类型是值类型,主要是数值类型和布尔类型。值类型是直接包含它们的数据,而不是包含存在内存其它地方的数据的引用。值类型的实例存在被称为堆的内存区域中,运行时能创建,读,更新,然后使用最小的开支去删除它们。
有三种值类型:
■ 内建类型
■ 用户自定义类型
■ 枚举类型
每种类型都继承System.Value 基本类型. 下列部分显示如何使用这些不同的类型。
内建值类型:
内建值类型是.NET Framework提供的基本类型,其它类型能够用它去构建。所有的内建数字类型都是值类型。你可以基于你操作的值得大小去选择一个数字类型及你所要求的精确度
表1列出了从最大到最小的最常用的数字类型。前六个用于所有数字类型后三个用于增加精确度。
Table 1-1 Built-in Value Types
Type(C# alias) Bytes Range Use for
System.SByte (sbyte) 1 –128 to 127 Signed byte values
System.Byte (byte) 1 0 to 255 Unsigned bytes
System.Int16 (short) 2 –32768 to 32767 Interoperation and other specialized uses
System.Int32 (int) 4 –2147483648 to 2147483647 Whole numbers and counters
System.UInt32 (uint) 4 0 to 4294967295 Positive whole numbers and counters
System.Int64 (long) 8 –9223372036854775808 to9223372036854775807 Large whole numbers
System.Single (float) 4 –3.402823E+38 to 3.402823E+38 Floating point numbers
System.Double (double) 8 –1.79769313486232E+308 to 1.79769313486232E+308 Precise or large floating point numbers
System.Decimal (decimal)16 –79228162514264337593543950335 to 79228162514264337593543950335 Financial and
scientific calculations
requiring
great precision
Note:
Optimizing performance with built-in types
运行时优化了32位整形(Int32 and UInt32),所以使用这些类型去计算和其它需频繁访问的整形变量.对于浮点型的操作, Double是最有效的类型因为这些操作被硬件优化了.
这些数字类型应用的很频繁,以至于C#语法中为它们定义了别名.使用别名等效于使用类型全名, 所以大部分程序员使用更短的别名.除了数字类型, 非数字类型列在表1-2中, 同时它们也使值类型.
Table 1-2 Other Value Types
Type (C# alias) Bytes Range Use for
System.Char(char) 2 N/A Single Unicode characters
System.Boolean(bool) 4 N/A True/False values
System.IntPtr (none) Platformdependent N/A Pointer to a memory address
System.DateTime(date) 8 1/1/000112:00:00 AM to12/31/999911:59:59 PM Moments in time
在Framework中有几乎300多的值类型,但显示在这的能满足大部分的需要.当你在值类型变量之间赋值时, 数据被从一个变量拷贝到其它变量, 并且在这个过程中数据被存在不同的位置.在这一点引用类型是不同的, 将在第二课讨论.
即使值类型总是代表着简单的值,它们是作为对象在运行.换句话说, 你能在它们上面调用方法.事实上,当值要以文本形式被显示出来时, ToString是一个被普遍使用的方法.
ToString重载了System.Object 类型的同名方法.
NOTE Object 基础类
在.NET Framework中,所有的类型都继承System.Object.这样的关系有利于通过Framework建立公共类型系统.
如何声明值类型:
为了使用一个类型,你必须首先声明一个符合作为这个类型的实例.值类型有一个隐性的构造器, 所以声明它们的同时就自动地实例化了这个类型;当你使用类时,不必为其赋值 .构造器会为这个新的实例赋上 一个默认值(通常是null或0)给新的实例,但你要在声明中显示地初始化这个变量,如下下程序显示的:
bool b = false;
如果你想要去确定一个值已经赋值了,声明一个变量为nullable.比如说,如果你在从一个表单上的yes/no的问题存储数据并且用户并没有回答问题,你应当存储一个null值.以下的代码可让一个Boolean变量是true,false,或其它的.
// C#
Nullable<bool> b = null;
// Shorthand notation, only for C#
bool? b = null;
NOTE .NET 2.0
The Nullable 是.NET2.0的一个新类型
声明一个nullable的变量,有HasValue和Value成员.使用HasValue去探测一个值是否被赋上:
// C#
if (b.HasValue)Console.WriteLine("b is {0}.", b.Value);
else Console.WriteLine("b is not set.");
如何创建用户定义类型:
用户自定义类型也被称struct,在这个关键字后去创建它们.用户自定义类型被存储在栈中, 并且直接包含变量的数据.在其它方面, 结构的特征几乎与类是一致的.结构是一个其它类型的组合, 使它能够更简单的与相关数据工作.结构最简单的例子是System.Drawing.Point, 它包括X和Y整数属性, 这量个属性定义了点的水平坐标和垂直坐标.Point结构通过提供构造器和成员简化了设置坐标的工作.显示如下:
// C# - Requires reference to System.Drawing
// Create point
System.Drawing.Point p = new System.Drawing.Point(20, 30);
// Move point diagonally
p.Offset(-1, -1);
Console.WriteLine("Point X {0}, Y {1}", p.X, p.Y);
你可以使用C#中的关键字struct去定义你自己的结构.比如: 以下的代码创建了一个类型,它通过结构的构造器去设定最大值和最小值,然后由最大值和最小值之间的整数去画圆.
// C#
struct Cycle
{
// Private fields
int _val, _min, _max;
// Constructor
public Cycle(int min, int max)
{
_val = min;
_min = min;
_max = max;
}
public int Value
{
get { return _val; }
set
{
if (value > _max)
_val = _min;
else
{
if (value < _min)
_val = _max;
else
_val = value;
}
}
}
public override string ToString()
{
return Value.ToString();
}
public int ToInteger()
{
return Value;
}
// Operators (new in .NET 2.0)
public static Cycle operator +(Cycle arg1, int arg2)
{
arg1.Value += arg2;
return arg1;
}
public static Cycle operator -(Cycle arg1, int arg2)
{
arg1.Value -= arg2;
return arg1;
}
}
NOTE .NET 2.0
Operator是.NET2.0中新的关键字。
使用operator关键字去重载一个内建的操作符或提供一个在类或结构的声明中的用户定义的类型转换。对于类型转换分为隐式和 显式转换 。
class Program
{
int aa, bb;
public Program(int a, int b)
{
this.aa = a;
this.bb = b;
}
public static Program operator +(Program a, Program b)
{
return new Program(a.aa + b.aa ,a.bb +b.bb );
}
public static Program operator -(Program a, Program b)
{
return new Program(a.aa - b.aa, a.bb - b.bb);
}
public static explicit operator int(Program a)
{
return a.aa + a.bb;
}
static void Main(string[] args)
{
Program p1 = new Program(1,1);
Program p2 = new Program(2,2);
int v= (int)(p1 +p2 -p2 );
Console .WriteLine ("{0}",v);
Console .ReadLine ();
}
}
返回值为2.
你能够使用这个结构去表现一些在一个范围内重复出现的项,比如说旋转度或足球游戏的四等分,如下所示:
// C#
Cycle degrees = new Cycle(0, 359);
Cycle quarters = new Cycle(1, 4);
for (int i = 0; i <= 8; i++)
{
degrees += 90; quarters += 1;
Console.WriteLine("degrees = {0}, quarters = {1}", degrees, quarters);
}
这个循环的例子能被简单的由一个值类型转换为一个引用类型,只需把struct关键字变为class关键字。如果你做了那个改变,Cycle类的实例将被分配在托管堆中,而不是占用12 bytes(每个私有整形占用4个bytes)的栈中, and assignment between two variables
results in both variables pointing to the same instance.
当功能比较简单时,结构比类更加有效。如果这个类型作为一个值类型比引用类型性能方面更好,你应该把它定义为一个结构。特别说明的是,要定义结构类型应当满足一下的表准:
■ 逻辑上,它代表一个单独的值。
■ 有一个小于16bytes的实例。
■创建之后不会改变
■ 不会被映射到一个引用类型。