第三章 对象和类型
类的成员
1.数据成员:字段,常量和事件
2.函数成员:方法,属性,构造函数,终结器,运算符,索引器
参数引用传递和值传递的区别:
1.在变量通过引用传递给方法时,被调用的方法得到的就是这个变量(的引用),所以在方法内部对变量进行的任何改变在方法退出后仍旧发挥作用.因为引用类型的对象只包含对象的引用,它们只给方法传递这个引用,而不是对象本身,所以对底层对象的修改会保留下来.
2.如果变量通过值传递给方法,被调用的方法得到的是变量的一个副本,也就是说,在方法退出后,对变量进行的修改会丢失.对于复杂的数据类型按照引用传递的效率较高,因为按值传递时必须复制大量的数据.值类型的对象包含的是实际数据,所以传递给方法的是数据本身的副本.例如,int通过值传递给方法,方法对该int的值所做的任何改变都没有改变原int对象的值
参数引用传递的特例:string
string作为参数传递是不同于其他引用类型的,因为字符串是不能改变的,如果改变字符串的值,就会创建一个全新的字符串.所以字符串无法采用一般引用类型的行为方式.在方法调用中,对字符串所做的任何改变都不会影响原来的字符串.
输入(ref)参数:通过值传送变量是默认的,但是可以迫使值参数通过引用传递给方法.如果把一个参数传递给方法,且这个方法的输入参数前带有ref关键字,则该方法对变量所做的任何改变都会影响原来对象的值.
out参数:out参数是一种特殊的ref参数.在C#中要求对传递给方法的参数进行初始化.在传递给方法之前,无论是按值传递,还是按引用传递,变量都必须初始化.如果在输入参数前面加上out关键字时,传递给该方法的变量可以不初始化,当然也可以对其初始化,但是没有意义.如果在函数体中没有给out参数分配一个值,该方法就不能编译.
方法overload:重载方法,只需要声明同名但参数个数或类型不同的方法即可.两点注意
1.两个方法不能仅在返回类型上有区别.
2.两个方法不能仅根据参数声明为ref还是out来区分
自动实现的属性:如果set和get访问器中没有任何逻辑,就可以使用自动实现的属性。这种属性会自动实现基础成员的变量,可以设置不同的访问级别。缺陷:
1.不能在自动属性中进行属性的有效性验证
2.必须有get,set两个访问器
默认构造函数:对于类,如果没有提供任何构造函数,编译器会在后台创建一个默认的构造函数。这是一个非常基本的构造函数,它只能把所有的成员字段初始化为标准的默认值。对于类,只有在没有定义任何构造函数时,编译器才会自动提供默认的构造函数。
私有构造函数的使用情况:
1.类仅用作某些静态成员或属性的容器,因此永远不会实例化
2.singleton模式.类仅希望调用某个静态成员函数来实例化
静态构造函数:
1.静态构造函数至多执行一次,即在代码引用类的静态成员成员或第一次实例化类之前执行,也就是说静态构造函数是在加载类时执行
2.没有访问修饰符
3.不能带参数
4.一个类只能由一个静态构造函数
5.可以与无参数的实例构造函数共存
6.如果静态字段有默认值,它们就在调用静态构造函数之前指定
构造函数初始化器:
1.this关键字仅调用参数最匹配的那个构造函数
2.构造函数初始化器在构造函数之前执行
3.可以包含对同一个类的另一个构造函数的调用,也可以包含对直接基类的构造函数的调用,但应使用base关键字代替this
4.初始化符不能有多个调用
只读字段
1.可以在构造函数中给只读字段赋值,也可以在声明时赋值,其为运行期动态解释的常量,区别于const
2.只读字段可以是一个实例字段,区别于const
3.在类的每个实例中可以有不同的值
4.可以用static修饰为静态
5.只读字段一般是公共的,不需要把只读字段设置为私有,因为按照定义,它们不能在外部修改
6.可以不必给只读字段赋值,如果没有赋值,它的值就是其数据类型的默认值,区别于const。const必须声明时赋值
匿名类型:匿名类型只是一个继承了Object的,没有名称的类。该类的定义从初始化器中推断,类似于隐式类型化的变量
结构与类的区别:
1.结构是值类型,不是引用类型。它们存储在堆栈中或存储为内联,其生存期的限制与简单的数据类型一样
2.结构不支持继承
3.结构的构造函数的工作方式与类有区别,其无参默认构造函数总是可用的并是不可代替的
4.结构中的字段大多数声明为public
5.初始化不一样
6.字段不能在定义结构时赋值,因为没有必要赋值,所有的字段都要在声明结构后初始化
结构的初始化3点注意:
1.结构可以不用new初始化
2.给结构的字段赋值实际上是为整个结构分配堆栈中的空间
3.new运算符并不分配堆中的内存,仅是调用相应的构造函数,根据传送给它的参数,初始化所有的字段。
4.结构中的所有元素必须进行初始化
初始化结构的3种形式:
1.调用new运算符
2.给结构的所有字段分别赋值
3.如果结构定义为类的成员,在初始化包含对象时,该结构会自动初始化为0
结构直接派生于System.ValueType,结构之间不支持继承
结构的构造函数:
1.禁止在C#的结构内定义无参的构造函数
2.结构的默认无参构造函数总是可用
3.不能在结构定义时为结构的字段赋值
部分类:partial关键字允许把类,结构或接口放在多个文件夹中,三点注意:
1.声明类时定义的访问级别,抽象,密封等约束将应用于该类的所有部分
2.可以有嵌套部分类
3.属性,接口,XML注释,特性等在编译后会合并
静态类:1.只能包含静态成员2.静态类不能被继承
object类:如果在定义类时没有指定基类,编译器就会自动假定这个类派生于Object。其方法:
1.ToString():获取对象的字符串表示的一种快捷方式,可以重写
2.GetHashTable():如果对象放在名为影射的数据结构中,就可以使用此方法确定确定对象放在结构的什么地方
3.Equals(),ReferenceEquals()比较对象地址相等性的不同方法
4.Finalize()在引用对象被回收,以清理资源时调用。类似于C++中的析构函数。通常要对非托管代码重写该方法释放内存
5.GetType()返回派生于System.Type派生的类的一个实例。System.Type提供了.NET反射技术的入口
6.MemberwiseClone()复制对象,返回一个对副本的引用,该方法不能被重写
扩展方法:其是一个静态方法,是类的一部分,但实际上没有放在类的源代码中。如果扩展方法与类中的某个方法同名,扩展方法就从来不会被调用。类中以后的实例方法优先。扩展方法的第一个参数为要扩展的类型,它放在this关键字后面。在扩展方法中可使用扩展类型的所有公共方法和属性。其载体必须是静态类.
扩展方法调用:
1.不显示第一个参数
2.即使扩展方法是静态的,也可以使用标准的实例方法语法调用它