zoukankan      html  css  js  c++  java
  • 《C#高级编程(第6版)》第3章筆記第3章对象和类型

    结构与类的区别是它们在内存中的存储方式(类是存储在堆(heap)上的引用类型,而结构是存储在堆栈(stack)上的值类型)、访问方式和一些特征(如结构不支持继承)。较小的数据类型使用结构可提高性能。但在语法上,结构与类非常相似,主要的区别是使用关键字struct代替class来声明结构。

    类成员----类中的数据和函数称为类的成员.
    数据成员包含了类的数据-- 字段、常量和事件。数据成员可以是静态数据(与整个类相关)或实例数据(类的每个实例都有它自己的数据副本)。通常,对于面向对象的语言,类成员总是实例成员,除非用static进行了显式的声明。
    函数成员提供了操作类中数据的某些功能,包括方法、属性、构造函数和终结器(finalizer)、运算符以及索引器。

    构造函数是在实例化对象时自动调用的函数。它们必须与所属的类同名,且不能有返回类型。构造函数用于初始化字段的值。

    终结器类似于构造函数,但是在CLR检测到不再需要某个对象时调用。它们的名称与类相同,但前面有一个~符号。

    给方法传递参数
    参数可以通过引用或值传递给方法。在变量通过引用传递给方法时,被调用的方法得到的就是这个变量,所以在方法内部对变量进行的任何改变在方法退出后仍旧发挥作用。而如果变量是通过值传送给方法的,被调用的方法得到的是变量的一个副本,也就是说,在方法退出后,对变量进行的修改会丢失。对于复杂的数据类型,按引用传递的效率更高,因为在按值传递时,必须复制大量的数据。

    在C#中,所有的参数都是通过值来传递的,除非特别说明。这与C++是相同的,但与Visual Basic相反。
    ref参数
    通过值传送变量是默认的,也可以迫使值参数通过引用传送给方法。为此,要使用ref关键字。如果把一个参数传递给方法,且这个方法的输入参数前带有ref关键字,则该方法对变量所作的任何改变都会影响原来对象的值
    out关键字
    编译器使用out关键字来初始化。在方法的输入参数前面加上out关键字时,传递给该方法的变量可以不初始化。该变量通过引用传送,所以在从被调用的方法中返回时,方法对该变量进行的任何改变都会保留下来。

    C#在重载方法的参数方面有一些小区别即可:

    ● 两个方法不能仅在返回类型上有区别。

    ● 两个方法不能仅根据参数是声明为ref还是out来区分。

    属性(property)不太常见,因为它们表示的概念是C#从Visual Basic中提取的,而不是从C++/Java中提取的。属性的概念是:它是一个方法或一对方法,在客户机代码看来,它们是一个字段。

    内联---即用内联代码来替代函数调用


    构造函数
    与Java 和 C++相同,没有必要给类提供构造函数,在我们的例子中没有提供这样的构造函数。一般情况下,如果没有提供任何构造函数,编译器会在后台创建一个默认的构造函数。这是一个非常基本的构造函数,它只能把所有的成员字段初始化为标准的默认值(例如,引用类型为空引用,数字数据类型为0,bool为false)。这通常就足够了,否则就需要编写自己的构造函数。

    构造函数的重载遵循与其他方法相同的规则。换言之,可以为构造函数提供任意多的重载,只要它们的签名有明显的区别即可.

    但注意,如果提供了带参数的构造函数,编译器就不会自动提供默认的构造函数,只有在没有定义任何构造函数时,编译器才会自动提供默认的构造函数。

    不能使用new运算符在外部代码中实例化,这在下面两种情况下是有用的:

    ● 类仅用作某些静态成员或属性的容器,因此永远不会实例化

    ● 希望类仅通过调用某个静态成员函数来实例化(这就是所谓对象实例化的类代理方法)

    编写静态构造函数的一个原因是,类有一些静态字段或属性,需要在第一次使用类之前,从外部源中初始化这些静态字段和属性。

    .NET运行库没有确保静态构造函数什么时候执行,所以不要把要求在某个特定时刻(例如,加载程序集时)执行的代码放在静态构造函数中。也不能预计不同类的静态构造函数按照什么顺序执行。但是,可以确保静态构造函数至多运行一次,即在代码引用类之前执行。在C#中,静态构造函数通常在第一次调用类的成员之前执行。
    注意,无参数的实例构造函数可以在类中与静态构造函数安全共存。尽管参数列表是相同的,但这并不矛盾,因为静态构造函数是在加载类时执行,而实例构造函数是在创建实例时执行,所以构造函数的执行不会有冲突。

    匿名类型
    匿名类型只是一个继承了Object的、没有名称的类。该类的定义从初始化器中推断,类似于隐式类型化的变量.

    结构
    在许多方面,可以把C#中的结构看作是缩小的类。它们基本上与类相同,但更适合于把一些数据组合起来的场合。它们与类的区别在于:

    ● 结构是值类型,不是引用类型。它们存储在堆栈中或存储为内联(inline)(如果它们是另一个保存在堆中的对象的一部分),其生存期的限制与简单的数据类型一样。

    ● 结构不支持继承。

    ● 结构的构造函数的工作方式有一些区别。尤其是编译器总是提供一个无参数的默认构造函数,这是不允许替换的。

    ● 使用结构,可以指定字段如何在内存中布局(第13章在介绍属性时将详细论述这个问题)。

    因为结构实际上是把数据项组合在一起,有时大多数甚至全部字段都声明为public。严格说来,这与编写.NET代码的规则相背-- 根据Microsoft,字段(除了const字段之外)应总是私有的,并由公共属性封装。但是,对于简单的结构,许多开发人员都认为公共字段是可接受的编程方式。

    结构是值类型,所以会影响性能,但根据使用结构的方式,这种影响可能是正面的,也可能是负面的。正面的影响是为结构分配内存时,速度非常快,因为它们将内联或者保存在堆栈中。
    在结构超出了作用域被删除时,速度也很快。另一方面,只要把结构作为参数来传递或者把一个结构赋给另一个结构(例如A=B,其中A和B是结构),结构的所有内容就被复制,而对于类,则只复制引用。这样,就会有性能损失,根据结构的大小,性能损失也不同。注意,结构主要用于小的数据结构。但当把结构作为参数传递给方法时,就应把它作为ref参数传递,以避免性能损失--此时只传递了结构在内存中的地址,这样传递速度就与在类中的传递速度一样快了。另一方面,如果这样做,就必须注意被调用的方法可以改变结构的值。


    partial关键字允许把类、结构或接口放在多个文件中。一般情况下,一个类存储在单个文件中。但有时,多个开发人员需要访问同一个类,或者某种类型的代码生成器生成了一个类的某部分,所以把类放在多个文件中是有益的。

    partial关键字的用法是:把partial放在class、struct或interface关键字的前面。


    Object类
    前面提到,所有的.NET类都派生于System.Object。实际上,如果在定义类时没有指定基类,编译器就会自动假定这个类派生于Object。本章没有使用继承,所以前面介绍的每个类都派生于System.Object(如前所述,对于结构,这个派生是间接的:结构总是派生于System.ValueType,System.ValueType派生于System.Object)。

    System.Object方法

    下面将简要总结每个方法的作用,下一节详细论述ToString()方法。

    ● ToString()方法:是获取对象的字符串表示的一种便捷方式。当只需要快速获取对象的内容,以用于调试时,就可以使用这个方法。在数据的格式化方面,它提供的选择非常少:例如,日期在原则上可以表示为许多不同的格式,但DateTime.ToString()没有在这方面提供任何选择。如果需要更专业的字符串表示,例如考虑用户的格式化配置或文化(区域),就应实现IFormattable接口(详见第8章)。

    ● GetHashTable()方法:如果对象放在名为映射(也称为散列表或字典)的数据结构中,就可以使用这个方法。处理这些结构的类使用该方法确定把对象放在结构的什么地方。如果希望把类用作字典的一个键,就需要重写GetHashTable()方法。对该方法重载的执行方式有一些相当严格的限制,这些将在第10章介绍字典时讨论。

    ● Equals()(两个版本)和ReferenceEquals()方法:如果把3个用于比较对象相等性的不同方法组合起来,就说明.NET Framework在比较相等性方面有相当复杂的模式。这3个方法和比较运算符==在使用方式上有微妙的区别。而且,在重写带一个参数的虚拟Equals()方法时也有一些限制,因为System.Collections命名空间中的一些基类要调用该方法,并希望它以特定的方式执行。第6章在介绍运算符时将探讨这些方法的使用。

    ● Finalize()方法:第12章将介绍这个方法,它最接近C++风格的析构函数,在引用对象被回收,以清理资源时调用。Finalize()方法的Object执行代码实际上什么也没有做,因而被垃圾收集器忽略。如果对象拥有对未托管资源的引用,则在该对象被删除时,就需要删除这些引用,此时一般要重写Finalize()。垃圾收集器不能直接重写该方法,因为它只负责托管的资源,只能依赖用户提供的Finalize()。

    ● GetType()方法:这个方法返回从System.Type派生的类的一个实例。这个对象可以提供对象所属类的更多信息,包括基本类型、方法、属性等。System.Type还提供了.NET反射技术的入口。这个主题详见第13章。

    ● MemberwiseClone()方法:这是System.Object中唯一没有在本书的其他地方详细论述的方法。不需要讨论这个方法,因为它在概念上相当简单,只是复制对象,返回一个对副本的引用(对于值类型,就是一个装箱的引用)。注意,得到的副本是一个浅表复制,即它复制了类中的所有值类型。如果类包含内嵌的引用,就只复制引用,而不复制引用的对象。这个方法是受保护的,所以不能用于复制外部的对象。该方法不是虚拟的,所以不能重写它的实现代码。


    扩展方法
    有许多方法扩展类。如果有类的源代码,继承(如第4章所述)就是给对象添加功能的好方法。但如果没有源代码,该怎么办?此时可以使用扩展方法,它允许改变一个类,但不需要类的源代码。

    申明

    非源创博文中的内容均收集自网上,若有侵权之处,请及时联络,我会在第一时间内删除.再次说声抱歉!!!

    博文欢迎转载,但请给出原文连接。

  • 相关阅读:
    【Elasticsearch 技术分享】—— ES 常用名词及结构
    【Elasticsearch 技术分享】—— Elasticsearch ?倒排索引?这都是什么?
    除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
    小伙伴想写个 IDEA 插件么?这些 API 了解一下!
    部署Microsoft.ReportViewe
    关于TFS强制undo他人check out
    几段查看数据库表占用硬盘空间的tsql
    How to perform validation on sumbit only
    TFS 2012 Disable Multiple Check-out
    在Chrome Console中加载jQuery
  • 原文地址:https://www.cnblogs.com/Athrun/p/1519320.html
Copyright © 2011-2022 走看看