收藏 分享(赏)

C#.NET基础知识.doc

上传人:11xg27ws 文档编号:7806113 上传时间:2019-05-26 格式:DOC 页数:97 大小:1.24MB
下载 相关 举报
C#.NET基础知识.doc_第1页
第1页 / 共97页
C#.NET基础知识.doc_第2页
第2页 / 共97页
C#.NET基础知识.doc_第3页
第3页 / 共97页
C#.NET基础知识.doc_第4页
第4页 / 共97页
C#.NET基础知识.doc_第5页
第5页 / 共97页
点击查看更多>>
资源描述

1、一:体系结构 2.NET Framework 平台体系结构 C#.2栈和托管堆/值类型和引用类型/强制类型转换/装箱和拆箱 C#.3一、 栈和托管堆 4二、类型层次结构 5三、引用类型 6四、预定义的引用类型 7五、强制类型转换 8六、装箱和拆箱(boxing/unboxing) 9二:方 法 10覆盖与重载(override/overload) C#.101. 方法签名与方法的显式隐藏 112. 方法重载与重写(overload 这一行。使用内建的别名 string 则不需要添加 using System;五、强制类型转换long x=12345;int k=(int) x; /发生收缩型强

2、制类型转换从较小数据类型到较大数据类型的转换称为扩展转换,否则称为收缩转换。编译器能进行隐式的扩展转换,对于收缩转换必须进行显式的强制性转换。因为收缩转换会导致丢失数据,在转换前我们要检查实际值是否超出目标类型的范围。另一个办法是使用 checked运算符,如果转换时丢失数据将抛出一个错误。强制类型转换即可针对值类型,又可针对引用类型。六、装箱和拆箱(boxing/unboxing)值类型和引用类型都是从 Object 类派生的。这意味着任何一个以对象为参数的方法,都可以给它传递一个值类型。相似地,值类型可以调用一个 Object 类方法:int j=4;string str=j.ToStri

3、ng();这里是另一个强制类型转换的例子。 您可能还记得,一个值类型变量包含存储在栈中的数据。您也许不明白值类型的变量如何调用一个引用类型的方法。答案是在一个称为装箱(boxing)的过程中,值类型变量被隐式转换为引用类型。从概念上来讲,装箱的过程就是对应值类型创建一个临时的引用类型的“箱子”。下面是 IL 代码:IL_000: ldc.i4.4 /Load the int 4 onto the stackIL_001: stloc.0 /Pop the value off the stack and into V_0IL_002: ldloca.s V_0 /Push the address

4、 of variable V_0 onto the stack/Call Int32:ToString()IL_004: call instance stringmscorlibSystem.Int32:ToString()关键的语句是 ldloca.s V_0,它加载指向 V_0 变量的一个托管指针。ToString()方法是在这个托管指针上调用,而不是在值本身调用。 还可以以下面正常的转换语法显式地将一个值装箱:int j=4;object ojb=(object) j;使用相同的类型转换语法可以把装箱的变量转换回值类型:int k=(int)obj;对拆箱操作有一些限制。 只能将显式装箱

5、的变量进行拆箱 。正常的强制转换中的限制在这里也适用。例如,如果把一个 long 型值装箱为一个对象,我们不能把该对象拆箱为一个 int 型值,虽然在拆箱后可以显式地把 long 转换为 int:long x=1000;object obj=(object) x;int i=(int)(long)obj);装箱与拆箱示意图:摘自二:方 法覆盖与重载(override/overload) C# 1. 方法签名与方法的显式隐藏以下程序中,子类 B 与父类 A 存在签名相同的函数,将产生方法隐藏。由于没有显式使用 new 修饰符,编译时出现警告。签名相同简单的讲是指忽略访问控制符、函数返回值、参数名

6、后其它内容相同。如:internal int Print(int x)public void Print(int y)protected float Print(int z)忽略访问控制符、返回值与参数名后都变成了 Print(int),所以它们都是签名相同的函数。public int Print(int x, int y) 和 public int Print(int x) 属于不同签名的函数public int Print(int X) 和 public int Print(float x) 属于不同签名的函数当 new 关键字用作修饰符时,可以在派生类中隐藏基类的方法,也就说在派生类的方

7、法是 new 关键字新定义出来的方法,而不是基类的方法。在不使用 New 关键字来隐藏基类方法也是可以的,编译器会出现一个警告,提示如果有意隐藏基类的方法,请使用 New关键字修饰。这种方法不应该过多地使用,因为它破坏了类型之间良好的继承关系,容易造成理解和维护上的困难。using System;using System.Collections.Generic;using System.Text;namespace LearnCSharpclass Ainternal void Print(int x)Console.WriteLine(“A: 0“, x);class B : A/当 A 中

8、的 Print()成员用 public、protected、internal 修饰,B 从 A 继承了 Print()方法时,会出现如下警告:/“LearnCSharp.B.Print()“隐藏了继承的成员“LearnCSharp.A.Print()“,如果是有意隐藏,请使用关键字 newpublic void Print(int y)Console.WriteLine(“B: 0“, y);class Ppublic static void Main(string args)A a = new A();a.Print(3);Console.ReadKey();B b = new B();b.

9、Print(4);Console.ReadKey(); 输出:A: 3B: 4用关键字 new,“LearnCSharp.B.Print()“ 显式隐藏了继承的成员“LearnCSharp.A.Print()“:using System;using System.Collections.Generic;using System.Text;namespace LearnCSharpclass Ainternal void Print(int x)Console.WriteLine(“A: 0“, x);class B : Apublic new void Print(int y)Console.

10、WriteLine(“B: 0“, y);class Ppublic static void Main(string args)A a = new A();a.Print(3);Console.ReadKey();B b = new B();b.Print(4);Console.ReadKey(); 输出:A: 3B: 4把基类中的 Print()方法变成 virtual 方法后:using System;using System.Collections.Generic;using System.Text;namespace LearnCSharpclass Ainternal virtual

11、 void Print(int x)Console.WriteLine(“A: 0“, x);class B : A/警告:“LearnCSharp.B.Print()“将隐藏继承的成员“LearnCSharp.A.Print()“ 。若要使当前成员重写该实现,/请添加关键字 override,否则添加关键字 new。public void Print(int y)Console.WriteLine(“B: 0“, y);class Ppublic static void Main(string args)A a = new A();a.Print(3);Console.ReadKey();B

12、 b = new B();b.Print(4);Console.ReadKey(); 输出:A: 3B: 4添加 override 关键字后:using System;using System.Collections.Generic;using System.Text;namespace LearnCSharpclass Apublic virtual void Print(int x)Console.WriteLine(“A: 0“, x);class B : Apublic override void Print(int y)Console.WriteLine(“B: 0“, y);cla

13、ss Ppublic static void Main(string args)A a = new A();a.Print(3);Console.ReadKey();B b = new B();b.Print(4);Console.ReadKey(); 输出:A: 3B: 4添加关键字 abstract 将类 A 变成抽象类后,无法创建抽象类或接口“LearnCSharp.A”的实例。修改后为:using System;using System.Collections.Generic;using System.Text;namespace LearnCSharpabstract class A

14、public virtual void Print(int x)Console.WriteLine(“A: 0“, x);class B : Apublic override void Print(int y)Console.WriteLine(“B: 0“, y);class Ppublic static void Main(string args)B b = new B();b.Print(4);Console.ReadKey(); 输出:B: 4以下程序展示了 new 和 override 的本质区别:using System;using System.Collections.Gener

15、ic;using System.Text;namespace LearnCSharpabstract class Apublic virtual void Print()Console.WriteLine(“这是虚方法“);class B1 : Apublic override void Print()Console.WriteLine(“这是新的方法“);class B2 : Apublic new void Print()Console.WriteLine(“这是另一个新的方法“);class Ppublic static void Main(string args)A a1 = new

16、B1();A a2 = new B2();a1.Print();a2.Print();Console.ReadKey(); 输出:这是新的方法这是虚方法总结:New 关键字主要用来区别派生类和基类同名方法的选择问题,通过隐藏基类方法,达到使编译器调用正确的方法的目的。Override 主要用来对基类的方法和虚方法进行重写。2. 方法重载与重写(overload public void EnglishGreeting(string name) Console.WriteLine(“Morning, “ + name);暂且不管这两个方法有没有什么实际意义。GreetPeople 用于向某人问好,

17、当我们传递代表某人姓名的 name 参数,比如说“Jimmy”,进去的时候,在这个方法中,将调用EnglishGreeting 方法,再次传递 name 参数,EnglishGreeting 则用于向屏幕输出 “Morning, Jimmy”。现在假设这个程序需要进行全球化,哎呀,不好了,我是中国人,我不明白“Morning” 是什么意思,怎么办呢?好吧,我们再加个中文版的问候方法:public void ChineseGreeting(string name)Console.WriteLine(“早上好, “ + name);这时候,GreetPeople 也需要改一改了,不然如何判断到底用

18、哪个版本的 Greeting 问候方法合适呢?在进行这个之前,我们最好再定义一个枚举作为判断的依据:public enum LanguageEnglish, Chinesepublic void GreetPeople(string name, Language lang)/做某些额外的事情,比如初始化之类,此处略swith(lang)case Language.English:EnglishGreeting(name);break;case Language.Chinese:ChineseGreeting(name);break;OK,尽管这样解决了问题,但我不说大家也很容易想到,这个解决方

19、案的可扩展性很差,如果日后我们需要再添加韩文版、日文版,就不得不反复修改枚举和 GreetPeople()方法,以适应新的需求。在考虑新的解决方案之前,我们先看看 GreetPeople 的方法签名:public void GreetPeople(string name, Language lang)我们仅看 string name,在这里, string 是参数类型,name 是参数变量,当我们赋给name 字符串“jimmy”时,它就代表“jimmy”这个值;当我们赋给它“张子阳”时,它又代表着“张子阳”这个值。然后,我们可以在方法体内对这个 name 进行其他操作。哎,这简直是废话么,刚

20、学程序就知道了。如果你再仔细想想,假如 GreetPeople()方法可以接受一个参数变量,这个变量可以代表另一个方法,当我们给这个变量赋值 EnglishGreeting 的时候,它代表着 EnglsihGreeting() 这个方法;当我们给它赋值 ChineseGreeting 的时候,它又代表着ChineseGreeting()方法。我们将这个参数变量命名为 MakeGreeting,那么不是可以如同给 name 赋值时一样,在调用 GreetPeople()方法的时候,给这个 MakeGreeting 参数也赋上值么(ChineseGreeting 或者 EnglsihGreetin

21、g 等)?然后,我们在方法体内,也可以像使用别的参数一样使用 MakeGreeting。但是,由于 MakeGreeting 代表着一个方法,它的使用方式应该和它被赋的方法(比如 ChineseGreeting)是一样的,比如:MakeGreeting(name);好了,有了思路了,我们现在就来改改 GreetPeople()方法,那么它应该是这个样子了:public void GreetPeople(string name, * MakeGreeting)MakeGreeting(name);注意到 * ,这个位置通常放置的应该是参数的类型,但到目前为止,我们仅仅是想到应该有个可以代表方法的

22、参数,并按这个思路去改写 GreetPeople 方法,现在就出现了一个大问题:这个代表着方法的 MakeGreeting 参数应该是什么类型的?NOTE:这里已不再需要枚举了,因为在给 MakeGreeting 赋值的时候动态地决定使用哪个方法,是ChineseGreeting 还是 EnglishGreeting,而在这个两个方法内部,已经对使用“morning”还是“早上好”作了区分。聪明的你应该已经想到了,现在是委托该出场的时候了,但讲述委托之前,我们再看看MakeGreeting 参数所能代表的 ChineseGreeting()和 EnglishGreeting()方法的签名:pu

23、blic void EnglishGreeting(string name)public void ChineseGreeting(string name)如同 name 可以接受 String 类型的“true”和“1”,但不能接受 bool 类型的 true 和 int 类型的 1 一样。MakeGreeting 的 参数类型定义 应该能够确定 MakeGreeting 可以代表的方法种类,再进一步讲,就是 MakeGreeting 可以代表的方法 的 参数类型和返回类型。于是,委托出现了:它定义了 MakeGreeting 参数所能代表的方法的种类,也就是MakeGreeting 参数的类型。NOTE:如果上面这句话比较绕口,我把它翻译成这样:string 定义了 name 参数所能代表的值的种类,也就是 name 参数的类型。本例中委托的定义:public delegate void GreetingDelegate(string name);可以与上面 EnglishGreeting()方法的签名对比一下,除了加入了 delegate 关键字以外,其余的是不是完全一样?现在,让我们再次改动 GreetPeople()方法,如下所示:

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报