版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、知识点1:引用和值类型总结从概念上看,值类型直接存储其值,而引用类型存储对其值的引用。这两种类型存储在内存的不同地方。在C#中,我们必须在设计类型的时候就决定类型实例的行为。这种决定非常重要,用CLR via C#作者Jeffrey Richter的话来 说,“不理解引用类型和值类型区别的程序员将会给代码引入诡异的bug和性能问题(I believe that a developer who misunderstands the difference between reference types and value types will introduce subtle bugs and p
2、erformance issues into their code.)”。这就要求我们正确理解和使用值类型和引用类型。1. 通用类型系统C#中,变量是值还是引用仅取决于其数据类型。C#的基本数据类型都以平台无关的方式来定义。C#的预定义类型并没有内置于语言中,而是内置于.NET Framework中。.NET使用通用类型系统(CTS)定义了可以在中间语言(IL)中使用的预定义数据类型,所有面向.NET的语言都最终被编译为 IL,即编译为基于CTS类型的代码。例如,在C#中声明一个int变量时,声明的实际上是CTS中System.Int32的一个实例。这具有重要的意义:确保IL上的强制类型安全;
3、 实现了不同.NET语言的互操作性; 所有的数据类型都是对象。它们可以有方法,属性,等。例如: int i;i = 1;string s;s = i.ToString();MSDN的这张图说明了CTS中各个类型是如何相关的。注意,类型的实例可以只是值类型或自描述类型,即使这些类型有子类别也是如此。2. 值类型C#的所有值类型均隐式派生自System.ValueType:结构体:struct(直接派生于System.ValueType);数值类型: 整 型:sbyte(System.SByte的别名),short(System.Int16),int(System.Int32),long (Sys
4、tem.Int64),byte(System.Byte),ushort(System.UInt16),uint (System.UInt32),ulong(System.UInt64),char(System.Char); 浮点型:float(System.Single),double(System.Double); 用于财务计算的高精度decimal型:decimal(System.Decimal)。 bool型:bool(System.Boolean的别名); 用户定义的结构体(派生于System.ValueType)。 枚举:enum(派生于System.Enum); 可空类型(派生于S
5、ystem.Nullable泛型结构体,T?实际上是System.Nullable的别名)。每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。例如:int i = new int();等价于:Int32 i = new Int32();等价于:int i = 0;等价于:Int32 i = 0;使用new运算符时,将调用特定类型的默认构造函数并对变量赋以默认值。在上例中,默认构造函数将值0赋给了i。MSDN上有完整的默认值表。关于int和Int32的细节,在我的另一篇文章中有详细解释:理解C#中的System.Int32和int。所有的值类型都是密封(seal)的,所以无法派生出新的
6、值类型。值得注意的是,System.ValueType直接派生于System.Object。即System.ValueType本身是一个类类型,而 不是值类型。其关键在于ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。可以用Type.IsValueType属性来判断一个类型是否为值类型:复制代码 代码如下:TestType testType = new TestType ();if (testTypetype.GetType().IsValueType)Console.WriteLine(0 is value type., testType.
7、ToString();3. 引用类型C#有以下一些引用类型:数组(派生于System.Array) 用户用定义的以下类型: 类:class(派生于System.Object); 接口:interface(接口不是一个“东西”,所以不存在派生于何处的问题。Anders在C# Programming Language中说,接口只是表示一种约定contract); 委托:delegate(派生于System.Delegate)。 object(System.Object的别名); 字符串:string(System.String的别名)。可以看出:引用类型与值类型相同的是,结构体也可以实现接口; 引
8、用类型可以派生出新的类型,而值类型不能; 引用类型可以包含null值,值类型不能(可空类型功能允许将 null 赋给值类型); 引用类型变量的赋值只复制对对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制包含的值。对于最后一条,经常混淆的是string。我曾经在一本书的一个早期版本上看到String变量比string变量效率高;我还经常听说String是引用类型,string是值类型,等等。例如:string s1 = Hello, ;string s2 = world!;string s3 = s1 + s2;/s3 is Hello, world!这确实看起来像
9、一个值类型的赋值。再如:string s1 = a;string s2 = s1;s1 = b;/s2 is still a改变s1的值对s2没有影响。这更使string看起来像值类型。实际上,这是运算符重载的结果,当s1被改变时,.NET在托管堆上为s1重新分配了内存。这样的目的,是为了将做为引用类型的string实现为通常语义下的字符串。4. 总结C#中,变量是值还是引用仅取决于其数据类型。C#的值类型包括:结构体(数值类型,bool型,用户定义的结构体),枚举,可空类型。C#的引用类型包括:数组,用户定义的类、接口、委托,object,字符串。数组的元素,不管是引用类型还是值类型,都存储
10、在托管堆上。引用类型在栈中存储一个引用,其实际的存储位置位于托管堆。为了方便,本文简称引用类型部署在托管推上。值类型总是分配在它声明的地方:作为字段时,跟随其所属的变量(实例)存储;作为局部变量时,存储在栈上。值类型在内存管理方面具有更好的效率,并且不支持多态,适合用作存储数据的载体;引用类型支持多态,适合用于定义应用程序的行为。应该尽可能地将值类型实现为具有常量性和原子性的类型。应该尽可能地确保0为值类型的有效状态。应该尽可能地减少装箱和拆箱。知识点2:封装可以把程序按某种规则分成很多“块“,块与块之间可能会有联系,每个块都有一个可变部分和一个稳定的部分。我们需要把可变的部分和稳定的部分分离
11、出来,将稳定的部分暴露给其他块,而将可变的部分隐藏起来,以便于随时可以让它修改。这项工作就是封装。例如:在用类实现某个逻辑的时候,类就是以上所说的块,实现功能的具体代码就是可变的部分,而public的方法或者属性则是稳定的部分。封装的意义封装的意义在于保护或者防止代码(数据)被我们无意中破坏。在面向对象程序设计中数据被看作是一个中心的原素并且和使用它的函数结合的很密切,从而保护它不被其它的函数意外的修改。封装提供了一个有效的途径来保护数据不被意外的破坏。相比我们将数据(用域来实现)在程序中定义为公用的(public)我们将它们(fields)定义为私有的(private)在很多方面会更好。私有
12、的数据可以用两种方式来间接的控制。下面我们看一些c#例子来学习这两种方法用以封装数据。第一种方法,我们使用传统的存、取方法。第二种方法我们用属性(property)。无论我们使用哪种的方法,我们的目标是在使用数据的同时不能使它受到任何的破坏和改变。有如下好处1、 使用者只需要了解如何通过类的接口使用类,而不用关心类的内部数据结构和数据组织方法。2、 高内聚,低耦合一直是我们所追求的,用好封装恰恰可以减少耦合3、 只要对外接口不改变,可以任意修改内部实现,这个可以很好的应对变化4、 类具有了简洁清晰的对外接口,降低了使用者的学习过程用传统的读、写方法封装让我们来看一个例子有一个类Grade(年级
13、信息类),为了操纵这个类中的数据(stringgradeName(年级名称)我们定义了一个读方法和一个写方法。 using system; public class Grade private string gradeName; . / 读方法 public string GetGradeName() return gradeName; /写方法 public void SetGradeName(string gradeName) this.gradeName=gradeName; 通过上面的方法,我们可以保护私有数据不被外部程序所破坏。现在我们使用两个不同的方法来写和读数据public st
14、aticvoid Main(string args)Grade grade = new Grade();grade.SetGradeName(S2)Console.WriteLine(TheGrade is :+grade.GetGradeName();在上面的例子中,我们不能直接访问类Grade的实例grade中的私有数据(stringgradeName),我们只能通过这两个方法来访问。用属性来实现封装属性是c#引入的一种语言成分,只有很少的语言支持属性。通过对属性的读和写来保护类中的域。第一种方法体身也是一种好的方式,但用属性来实现封装会更方便。现在我们来看一个例子: using syst
15、em; public class Grade private string gradeName; public string GradeName get return gradeName; set gradeName =value; public static void Main(string args) Grade grade= newGrade (); grade.GradeName=S2; Console.WriteLine(TheGrade is :0,grade.GradeName); 通过上面的例子,我们可以看到如何通过属性来实现封装。属性具有两种操作get和set。get用来返回
16、属性域的值。set通过value这个变量来给属性域赋值。属性可以设为只读的(read-only)。这只需属性只具有一个set操作。只读属性public string GradeName get return gradeName; 在上面的例子中我们看到了如何来实现一个只读的属性。类Grade拥有一个GradeName属性只实现了get操作。它省略了写操作。这个特别的类拥有一个构造器,用来接受一个字符串变量。在Main方法创建了一个新的对象grade。对象grade的实例使用了类Grade带有一个字符串参数的构造器。因为上面的属性是只读的,所以我们不给域gradeName赋值并且我们只侧读取此域
17、中的值。当然属性也可以是只写的(write-only),这只需属性只具有一个get操作。public string GradeName set this.gradeName = value; 在上面的例子中我们看到了如何来实现一个只写的属性。类Grade拥有一个GradeName属性只实现了set操作。它省略了读操作。 总结封装是朝着面向对象程序设计迈出的第一步。本文主要展示了一些封装的知识。用传统的读、写两种方法可以实现封装,另一种实现封装的方法是使用属性。使用属性的好处在于对象的使用者可以用一条语句来操作内部的数据知识点3:继承 一、 继承的定义二、为了提高软件模块的可复用性和可扩充性,以
18、便提高软件的开发效率,我们总是希望能够利用前人或自己以前的开发成果,同时又希望在自己的开发过程中能够有足够的灵活性,不拘泥于复用的模块。C#这种完全面向对象的程序设计语言提供了两个重要的特性-继承性inheritance 和多态性polymorphism。继承是面向对象程序设计的主要特征之一,它可以让您重用代码,可以节省程序设计的时间。继承就是在类之间建立一种相交关系,使得新定义的派生类的实例可以继承已有的基类的特征和能力,而且可以加入新的特性或者是修改已有的特性建立起类的新层次。现实世界中的许多实体之间不是相互孤立的,它们往往具有共同的特征也存在内在的差别。人们可以采用层次结构来描述这些实体
19、之间的相似之处和不同之处。为了用软件语言对现实世界中的层次结构进行模型化,面向对象的程序设计技术引入了继承的概念。一个类从另一个类派生出来时,派生类从基类那里继承特性。派生类也可以作为其它类的基类。从一个基类派生出来的多层类形成了类的层次结构。注意:C#中,派生类只能从一个类中继承。这是因为,在C+中,人们在大多数情况下不需要一个从多个类中派生的类。从多个基类中派生一个类这往往会带来许多问题,从而抵消了这种灵活性带来的优势。C#中,派生类从它的直接基类中继承成员:方法、域、属性、事件、索引指示器。除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员二、C#中的继承符合下列规则:1、继承
20、是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。Object 类作为所有类的基类。2、派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去已经继承的成员的定义。3、构造函数和析构函数不能被继承。除此以外的其它成员,不论对它们定义了怎样的访问方式,都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。4、派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。5、类可以定义虚方法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态
21、性。6、派生类只能从一个类中继承,可以通过接吕实现多重继承。下面的代码是一个子类继承父类的例子:三. 访问与隐藏基类成员(1) 访问基类成员通过base 关键字访问基类的成员: 调用基类上已被其他方法重写的方法。 指定创建派生类实例时应调用的基类构造函数。 基类访问只能在构造函数、实例方法或实例属性访问器中进行。从静态方法中使用 base 关键字是错误的。(2) 隐藏基类成员想想看,如果所有的类都可以被继承,继承的滥用会带来什么后果?类的层次结构体系将变得十分庞,大类之间的关系杂乱无章,对类的理解和使用都会变得十分困难。有时候,我们并不希望自己编写的类被继承。另一些时候,有的类已经没有再被继承
22、的必要。C#提出了一个密封类(sealed class)的概念,帮助开发人员来解决这一问题。密封类在声明中使用sealed 修饰符,这样就可以防止该类被其它类继承。如果试图将一个密封类作为其它类的基类,C#将提示出错。理所当然,密封类不能同时又是抽象类,因为抽象总是希望被继承的。在哪些场合下使用密封类呢?密封类可以阻止其它程序员在无意中继承该类。而且密封类可以起到运行时优化的效果。实际上,密封类中不可能有派生类。如果密封类实例中存在虚成员函数,该成员函数可以转化为非虚的,函数修饰符virtual 不再生效。(3) 密封方法我们已经知道,使用密封类可以防止对类的继承。C#还提出了密封方法(sea
23、ledmethod) 的概念,以防止在方法所在类的派生类中对该方法的重载。对方法可以使用sealed 修饰符,这时我们称该方法是一个密封方法。不是类的每个成员方法都可以作为密封方法密封方法,必须对基类的虚方法进行重载,提供具体的实现方法。所以,在方法的声明中,sealed 修饰符总是和override 修饰符同时使用。(4) 使用 new 修饰符隐藏基类成员使用 new 修饰符可以显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。通过继承隐藏名称采用下列形式之一: a、引入类或结构中的常数、指定、属性或类型隐藏具有相同名称的所有基类成
24、员。 b、引入类或结构中的方法隐藏基类中具有相同名称的属性、字段和类型。同时也隐藏具有相同签名的所有基类方法。 c、引入类或结构中的索引器将隐藏具有相同名称的所有基类索引器。 注意:在同一成员上同时使用 new 和 override 是错误的。同时使用 new 和 virtual 可保证一个新的专用化点。在不隐藏继承成员的声明中使用 new 修饰符将发出警告。四、多级继承一些面向对象语言允许一个类从多个基类中继承,而另一些面向对象语言只允许从一个类继承,但可以随意从几个接口或纯抽象类中继承。只有C+支持多级继承,许多程序员对此褒贬不一。多级继承常会引起继承来的类之间的混乱,继承而来的方法往往没
25、有唯一性,所以C#中类的继承只可以是一个,即子类只能派生于一个父类,而有时你必须继承多个类的特性,为了实现多重继承必须使用接口技术。五、继承与访问修饰符访问修饰符是一些关键字,用于指定声明的成员或类型的可访问性。类的继承中有四个访问修饰符: public protected internal private。使用这些访问修饰符可指定下列五个可访问性级别: public protected internal internal protected private。声明的可访问性意义public访问不受限制。protected访问仅限于包含类或从包含类派生的类型。internal访问仅限于当前项目。
26、protected internal访问仅限于从包含类派生的当前项目或类型。private访问仅限于包含类型。1、继承中关于可访问域的一些问题基类的所有成员(实例构造函数、析构函数和静态构造函数除外)都由派生类型继承。这甚至包括基类的私有成员。但是,私有成员的可访问域只包括声明该成员的类型的程序文本。2、继承中关于属性的一些问题和类的成员方法一样,我们也可以定义属性的重载、虚属性、抽象属性以及密封属性的概念。与类和方法一样,属性的修饰也应符合下列规则:属性的重载1. 在派生类中使用修饰符的属性,表示对基类中的同名属性进行重载。2. 在重载的声明中,属性的名称、类型、访问修饰符都应该与基类中被继承的属性一致。3. 如果基类的属性只有一个属性访问器,重载后的属性也应只有一个。但如果基类的属性同时包含get 和set 属性访问器,重载后的属性可以只有一个,也可以同时有两个属性访问器。注意:与方法重载不同的是,属性的重载声明实际上并没有声明新的属性,而只是为已有的虚属性提供访问器的具体实现。虚属性1. 使用virtual 修饰符声明的属性为虚属性。2. 虚属性的访问器包括get 访问器和set 访问器,同样也是虚的。抽象属性1. 使用abstract 修饰符声明的属性为抽象属性。2. 抽象属性的访问器也是虚的,而且没有提供访问器的具体实现
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 施工现场信息化管理方案
- 高校心理咨询师职业发展方案
- 2024-2025学年新教材高中政治第三单元文化传承与文化创新第8课第1框文化的民族性与多样性课时作业含解析部编版必修4
- 2024-2025学年新教材高中英语Unit4HistoryandTraditionsDiscoveringUsefulStructures课时素养评价含解析新人教版必修2
- 2024-2025学年新教材高中政治第三单元文化传承与文化创新第9课第3框文化强国与文化自信课时作业含解析部编版必修4
- 2024-2025学年八年级历史下册第五单元国防建设与外交成就第15课钢铁长城练习题新人教版
- 2024-2025年新教材高中物理第2章抛体运动1.2小船渡河和关联速度问题课时练习含解析鲁科版必修2
- 新教材高中政治7.1世界是普遍联系的作业3含解析新人教版必修4
- 2024-2025学年高中数学第一章统计1.5.2估计总体的数字特征课时素养评价含解析北师大版必修3
- 2024年学校家具安装与维护合同
- 二手车拍卖成交确认书范本简约版
- 教师资格的定期注册申请表
- 淡水养殖技术培训
- 海思芯片HTOL老化测试技术规范
- 小学音乐人音四年级上册(2023年新编)第5课童心-《荡秋千》教学设计
- 四年级数学上册课件-8. 沏茶 -人教版(共14张PPT)
- 计算书水泵耗电输冷比
- 四年级英语上册课件-Unit 4 My home Lets learn -人教PEP版(共20张PPT)
- 最新版个人征信报告(可编辑+带水印)
- 人卫版内科学下丘脑疾病
- 三年级上册美术课件第10课 美丽的路灯|沪教版
评论
0/150
提交评论