《csharp高级编程》 学习笔记 第三章 对象和类型

第三章 对象和类型
3.1 类和结构
类和结构实际上都是创建对象的模板。
类和结构的区别是他们在内存中的存储方式:
类是存储在堆(heap)上的引用类型,而结构是存储在堆栈(stack)上的值类型、访问方式和一些特征(如结构不支持继承)。
但在语法上,两者非常相似。
对于类和结构,都是用关键字new来声明实例:这个关键字创建对象并对其进行初始化。


3.2 类成员
类中的数据和函数成为类的成员。


3.2.1 数据成员
数据成员包含了类的数据--字段、常量和事件。
数据成员可以是静态数据成员或实例数据(类的每个实例都有它自己的数据副本)。
1.字段是与类相关的变量。
2.常量与类的关联方式同变量与类的关联方式一样。
3.事件是类的成员,在发生某些行为(例如改变类的字段或属性,或者进行了某种形式的用户交互操作)时,它可以让对象通知调用程序。客户可以包含所谓“事件处理程序”的代码来响应该事件。
3.2.2 函数成员
函数成员提供了操作类中数据的某些功能,包括如下:
1.方法:
与每个类相关的函数,可以是实例方法,也可以是静态方法。
注意静态方法不需要实例化一个类就可以调用(例如Console.WriteLine()方法)。
大部分与c++相同。
但是需要注意几点特殊的地方如下:


(1)ref参数
通过值传送变量是默认的,但是也可以迫使值参数通过引用传送给方法。
void SomeFunction(ref int i)
{
i=100;//the change to i will persist after SomeFunction() exits
}
注意在调用该方法时,需要添加ref关键字:SomeFunction(ref i);
而且,csharp要求对传递给方法的参数进行初始化,无论是按值传递,按引用传递,变量都必须初始化,除了out关键字。
(2)out关键字
编译器使用out关键字来初始化。在方法的输入参数前面加上out,传递给该方法的变量可以不初始化。
同理ref,调用函数时也要使用out。
(3)函数重载
注意不能仅根据参数声明为ref还是out来区分。


2.属性:
可以在客户机上访问的函数组,其访问方式与访问类的公共字段类似。
即那些set、 get。
概念:它是一个方法或一对方法,在客户机代码看来,他们是一个字段。
private string foreName;
public string ForeName
{
get
{
return foreName;
}
set
{
foreName = value;
}
}
(1)只读和只写属性。
(2)属性的访问修饰符
(3)自动实现的属性
如果属性的set和get访问器中没有任何逻辑,就可以使用自动实现的属性。
这种属性会自动实现基础成员变量。
上例的代码如下:
public string ForeName {get; set;}
不需要声明private string foreName。编译器会自动创建它。
public string ForeName {get; }//错误,因为不能只设置为只读。
public string ForeName {get; private set;}//正确,访问级别可以不同
(4)内联
JIT编译器可生成高度优化的代码,并在适当的时候使用内联代码。
故不必担心因为用属性来访问字段而造成性能损失。


3.构造函数
需要注意的是默认的构造函数有初始化所有的成员字段为标准的默认值。
注意:
和c++一样,只有在没有定义任何构造函数时,编译器才会自动提供默认的构造函数。
可以把构造函数定义为private或protected,使不相关的类不能访问它们。


(1).静态构造函数:
csharp的一个新特性是可以给类编写无参数的静态构造函数。
这种构造函数只执行一次,而前面的构造函数是实例构造函数,只要创建对象都会执行。


编写静态构造函数的一个原因是:
有时候需要在第一次使用类之前,从外部源中初始化一些静态字段和属性。
*静态构造函数通常在第一次调用类的成员之前执行,总是由.NET运行库调用它,但精确什么时候执行我们无法得知。
*静态构造函数没有访问修饰符,不带任何参数。
*一个类只能有一个静态构造函数,
*无参数的实例构造函数可以喝类中与静态构造函数安全共存。
*如果多个类都有静态构造函数,先执行哪个静态构造函数是不确定的。
*静态字段有默认值,它们就在调用静态构造函数之前指定。


(2).从其他构造函数中调用构造函数
public Car(string description, uint nWheels){}
public Car(string description) : this(model, 4);
将this换成base可以对直接基类的构造函数的调用。
*构造函数初始化符语法上类似c++构造函数初始化列表,但其实遵循完全不同的规则。
csharp初始化符中的代码只能调用另一个构造函数。
4.终结器:
类似于C++的构造函数,但是在CLR检测到不再需要某个对象时自动调用。
注意:不可能预测什么时候调用终结器。
5.运算符:
运算符重载。
6.索引器:
索引器允许对象以数组或者集合的方式进行索引。


3.2.3 只读字段readonly
与常量不同的地方在于在运行之前值未知。


3.3 匿名类型
var 和 new 关键字一起使用时,可以创建匿名类型。
匿名类型只是一个继承了object的,没有名称的类。
该类的定义从初始化器中推断,类似隐式类型化的变量。
var captain = new {FirstName = "James", MiddleName = "T",LastName = "Kirk"};
这些新对象的类型名是未知的。编译器为类型"伪造"了一个名称,但只有编译器才能使用它。


3.4 结构
类提供的功能多于我们需要的功能,由于性能的原因,最好使用结构。
*为结构定义函数与类完全相同。
*csharp在许多方面可以把结构看成是缩小的类。
结构和类的区别:
(1)结构是值类型,结构的new运算符与类工作方式不同。
new运算符并不分配堆中的内存,而是调用相应的构造函数。
(2)结构不能继承
(3)结构的默认构造函数是始终存在的。


3.5 部分类
partial关键字允许把类,结构或接口放在多个文件中。


3.6 静态类
如果类只包含静态的方法和属性,该类就是静态的。
静态类在功能上与使用私有静态构造函数创建的类相同。
不能创建静态类的实例。
使用static关键字,编译器可以检查以后是否给该类添加了实例成员。如果是则编译错误。
static class StaticUtilities
{
public static void HelperMethod()
{
}
}


3.7 Object类
定义类没有指定基类,编译器会自动假定这个类派生于Object。
*对于结构,这个派生是间接的:
结构总是派生于System.ValueType,System.ValueType派生于System.Object。
3.7.1 System.Object方法
● ToString()
● GetHashTable()
● Equals()(两个版本)和ReferenceEquals()方法:
● Finalize()
● GetType()
● MemberwiseClone()
后面章节会具体解释这些函数。


3.8 扩展方法
允许改变一个类,但不需要类的源代码。
扩展方法是静态方法,是类的一部分,但实际上没有放在类的源代码中。

你可能感兴趣的:(编程,String,object,equals,存储,编译器)