C#经典问题回答_第1页
C#经典问题回答_第2页
C#经典问题回答_第3页
C#经典问题回答_第4页
已阅读5页,还剩64页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

TOC\o"1-5"\h\z.静态成员和非静态成员的区别? 1\o"CurrentDocument".const和staticreadonly区别? 3.extern是什么意思? 6.abstract是什么意思? 85.internal修饰符起什么作用? 136.sealed修饰符是干什么的? 16\o"CurrentDocument"7.override和overload的区别? 20.什么是索引指示器? 22.new修饰符是起什么作用? 25.可以使用抽象函数重写基类中的虚函数吗? 28.密封类可以有虚函数吗? 29.什么是属性访问器? 29.abstract可以和virtua!一起使用吗?可以和override一起使用吗? 30.接口可以包含哪些成员? 30.类和结构的区别? 30.接口的多继承会带来哪些问题? 34.抽象类和接口的区别? 37.静态成员和非静态成员的区别?答:静态变量使用static修饰符进行声明,在类被实例化时创建,通过类进行访问不带有static修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问ー个类的所有实例的同一静态变量都是同一个值,同・个类的不同实例的同一非静态变量可以是不同的值静态函数的实现里不能使用非静态成员,如非静态变量、非静态函数等示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExampleO1classProgramclassClassipublicstaticStringstaticStr="Class”;publicStringnotstaticStr="Obj";staticvoidMain(string[]args)〃静态变量通过类进行访问,该类所有实例的同一静态变量都是同一个值Console.WriteLine("ClassrsstaticStr:{0}",Classi.staticStr);ClassitmpObjl=newClassi():tmpObjl.notstaticStr="tmpObjl";ClassitmpObj2=newClassi();tmpObj2.notstaticStr="tmpObj2";〃非静态变量通过对象进行访问,不同对象的同一非静态变量可以有不同的值Console.WriteLine("tmpObjl,snotstaticStr:{0},tmpObjl.notstaticStr);Console.WriteLine("tmpObj2*snotstaticStr:{0}",tmpObj2.notstaticStr);Console.ReadLineO;结果:Classi'sstaticStr:ClasstmpObjl'snotstaticStr:tmpObjltmpObj2'snotstaticStr:tmpObj2.const和staticreadonly区别?答:const用const修饰符声明的成员叫常量,是在编译期初始化并嵌入到客户端程序staticreadonly用staticreadonly修饰符声明的成员依然是变量,只不过具有和常量类似的使用方法:通过类进行访问、初始化后不可以修改。但与常量不同的是这种变量是在运行期初始化示例:测试类:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExampleO2Lib

publicclassClassipublicconstStringstrConst="Const”;publicstaticreadonlyStringstrStaticReadonly=MStaticReadonlyH;//publicconstStringstrConst="ConstChanged";//publicstaticreadonlyStringstrStaticReadonly="StaticReadonlyChanged";))客户端代码:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingExample02Lib;namespaceExample02(classProgramstaticvoidMain(string[]args)

//修改Example02中Class!的strConst初始值后,只编译ExampleO2Lib项目//然后到资源管理器里把新编译的ExampleO2Lib.dll拷贝Example。2.exe所在的目录,执行Example02.exe//切不可在[DE里直接调试运行因为这会重新编译整个解决方案!!//可以看到strConsセ的输出没有改变,而strStaticReadonly的输出已经改变//表明Const变量是在编译期初始化并嵌入到客户端程序,而StaticReadonly是在运行时初始化的Console.WriteLine("strConst:{〇}",Classi.strConst);Console.WriteLine("strStaticReadonly:{0}",Classi.strStaticReadonly);Console.ReadLine();}))结果:strConst:ConststrStaticReadonly:StaticReadonly修改后的示例:

测试类:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExampleO2Lib(publicclassClassi{//publicconstStringstrConst="Const”;//publicstaticreadonlyStringstrStaticReadonly="StaticReadonly”;publicconstStringstrConst="ConstChanged";publicstaticreadonlyStringstrStaticReadonly="StaticReadonlyChanged";})结果strConst:ConststrStaticReadonly:StaticReadonlyChanged.extern是什么意思?

答:extern修饰符用于声明由程序集外部实现的成员函数经常用于系统API函数的调用(通过Dlllmport)〇注意,和Dlllmportー起使用时要加上static修饰符也可以用于对于同一程序集不同版本组件的调用(用extern声明别名)不能与abstract修饰符同时使用示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Runtime.InteropServices;namespaceExample03(classProgram(//注意Dlllmport是ー个AttributeProperty»在System.Runtime.InteropServices命名空间中定义//extern与Dlllmport一・起使用时必须再加上一・个static修饰符[Dlllmport(nUser32.dllM)]publicstaticexternintMessageBox(intHandle,stringMessage,stringCaption,intType);

staticintMain()stringmyString;Console.Write("Enteryourmessage:")myString=Console.ReadLine();returnMessageBox(0,myString,"MyMessageBox",0);结果:4.abstract是什么意思?答:abstract修饰符可以用于类、方法、属性、事件和索引指示器(indexer),表示其为抽象成员abstract不可以和static、virtua!一起使用声明为abstract成员可以不包括实现代码,但只要类中还有未实现的抽象成员(即抽象类),那么它的对象就不能被实例化,通常用于强制继承类必须实现某ー成员

示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample04(#region基类,抽象类publicabstractclassBaseClass{//抽象属性,同时具有get和set访问器表示继承类必须将该属性实现为可读写publicabstractStringAttribute{get;set;}//抽象方法,传入一个字符串参数无返回值publicabstractvoidFunction(Stringvalue);//抽象事件,类型为系统预定义的代理(delegate):EventHandlerpublicabstracteventEventHandlerEvent;//抽象索引指示器,只具有get访问器表示继承类必须将该索引指示器实现为只读publicabstractCharthis[intIndex](get;}}#endregion#region继承类publicclassDeriveClass:BaseClass(privateStringattribute;publicoverrideStringAttribute(getreturnattribute;

setattribute=value;})publicoverridevoidFunction(Stringvalue)(attribute=value;if(Event!=null){Event(this,newEventArgs());})publicoverrideeventEventHandlerEvent;publicoverrideCharthis[intIndex](get{returnattribute[Index];}#endregionclassProgram{staticvoidOnFunction(objectsender,EventArgse)(for(inti=0;i<((DeriveClass)sender).Attribute.Length;i++)(Console.WriteLine(((DeriveClass)sender)[i]);)}staticvoidMain(string[]args){DeriveClasstmpObj=newDeriveClass();tmpObj.Attribute="1234567”;Console.WriteLine(tmpObj.Attribute);//将静态函数OnFunction与tmpObj对象的Event事件进行关联tmpObj.Event+=newEventHandler(OnFunction);

tmpObj.Function(“7654321");Console.ReadLine();)})结果:123456776543215.internal修饰符起什么作用?答:internal修饰符可以用于类型或成员,使用该修饰符声明的类型或成员只能在同一程集内访问接口的成员不能使用interna!修饰符

值得注意的是,如果为internal成员加上了protected修饰符,这时的访问级别为interna!或protected,只是看字面意思容易弄错,许多人认为internalprotected应该是、、只有同一个程序集中的子类可以访问〃,但其实它表示、、同一个程序集中的所有类,以及所有程序集中的子类都可以访问“示例ExampleO5Lib项目的ClassiusingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample05Lib(publicclassClassi{internalStringstrinternal=null;publicStringstrPublic;internalprotectedStringstrInternalProtected=null;

结果ExampleO5Lib项目的Class2类可以访问到Class!的strinternal成员,当然也可以访问到strinternaIProtected成员,因为他们在同一个程序集里ClassZxs*Classi.cs*済ExampleO511b,e屈$2 v/BusingSyittm.Iusia<System.CollectionsGeneric;LusiySystem.Text;BnwespaceEx«mpleO5LibH Cltss2(privateStringtapStr-newClassi0.|:} } キEquals ♦GetHashCodeQGetTypeザ由InternalRstrlnternalProtected0strPublic令ToStrlngClarkZhengExample05项目里的Class3类无法访问到Classi的strinternal成员,因为它们不在同一个程序集里。但却可以访问到strlnternaIProtected成员,因为Class3是Classi的继承类Program.cs*Class2.csGassl.cs出Examp*e05,Program.Oas$3System;usin<System.CollectionsGeneric;usin^System.Text;Lusin^ExampleOSLib;BntBespaceExample05BclassProp*miB classClass3:Classi1 1pMcSい。(base.)3 staticvo(Strin)J.Equals♦GetHashCode〇GetType:"MemberwiseCfonestrPublic;strInternalProtected|$tringOassl.strlnternalPrcQstrPubk♦ToStringClarkZhengExample05项目的Program类既无法访问到Classistrinternal成员,也无法访问到strInternalProtected成员,因为它们既不在同一个程序集里也不存在继承关系Oass2.cs*Oassl.csProgram.cs*BusingSystem.BusingSystem.usiySystem.Collections.Generic;usin<SystemText;Lusin<Ex«mpl«05Lib.日n.”pac.ExMipl«05HBclassrrogra»B staticvoidlain(strin([]«r(s)StrinctapStr=n«wClassi0.啕EqualsAGetHashCodeQGetTypeQ加Public9ToString~CtartcZhehg6.sealed修饰符是干什么的?答:sealed修饰符表示密封用于类时,表示该类不能再被继承,不能和abstract同时使用,因为这两个修饰符在含义上互相排斥用于方法和属性时,表示该方法或属性不能再被重写,必须和override关键字一起使用,因为使用sealed修饰符的方法或属性肯定是基类中相应的虚成员通常用于实现第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承造成层次结构体系混乱恰当的利用sealed修饰符也可以提高一定的运行效率,因为不用考虑继承类会重写该成员示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample06(classProgram(classA{publicvirtualvoidF()

publicvirtualvoidG()Console.WriteLine(nA.Gn);))classB:A(publicsealedoverridevoidF()(Console.WriteLine(nB.Fn);}publicoverridevoidG()(Console.WriteLine(MB.Gn);))classC:B(publicoverridevoidG()Console.WriteLine("C.G");

args)staticvoidMain(string[](args)newA().F();newA().G();newB().F();newB().G();newC().F();newC().G();Console.ReadLine();}})结果:类B在继承类A时可以重写两个虚函数,如图所示:classApubl1cvirtualvoidF0Console.WriteLine(*JLF*);}publ1cvirtualvoidGOConsoleWriteLine(*A.G");clastBApublicsealedoverridevoid0G()中对F方法进行/密封,类C在继承类B时只能重写ー个函数,如图所示:classB:A[publics«<l«dov«rrid«voidF(){Console.WriteLine(*B.F*);}publicoverridevoidGO(Console,tfriteLine(*B.G");J1classC:BIpublicoverridevoidIirzTx—j|Y?Y JClarkZheng控制台输出结果,类C的方法F只能是输出类B中对该方法的实现:A.FA.GB.FB.GB.FC.G7.override和overload的区别?答:override表示重写,用于继承类对基类中虚成员的实现overload表示重载,用于同一个类中同名方法不同参数(包括类型不同或个数不同)的实现示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample07(classProgram(classBaseClass(publicvirtualvoidF(){Console.WriteLine("BaseClass.F");})classDeriveClass:BaseClass{publicoverridevoidF(){base.F();Console.WriteLine(nDeriveClass.Fu);}publicvoidAdd(intLeft,intRight)(Console.WriteLine("AddforInt:{0}",Left+Right);}publicvoidAdd(doubleLeft,doubleRight){Console.WriteLine("Addforint:{0}",Left+Right);))staticvoidMain(string[]args)(DeriveClasstmpObj=newDeriveClass();tmpObj.FO;tmpObj.Add(l,2);tmpObj.Add(1.1,2.2);Console.ReadLine();结果:BaseClass.FDeriveClass.FAddforInt:3Addforint:3.38.什么是索引指示器?答:实现索引指示器(indexer)的类可以象数组那样使用其实例后的对象,但与数组不同的是索引指示器的参数类型不仅限于int简单来说,其本质就是一个含参数属性示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample08(publicclassPoint(privatedoublex,y;publicPoint(doubleX,doubleY)(x=X;y=Y;I〃重写ToString方法方便输出publicoverridestringToStringO(returnString.FormatC'X:{0},Y:{1x,y);))publicclassPoints(Point[]points;publicPoints(Point[]Points)(points=Points;)publicintPointNumber(getreturnpoints.Length;〃实现索引访问器publicPointthis[intIndex]{get{returnpoints[Index];}})〃索引指示器的实质是含参属性,参数并不只限于intclassWeatherOfWeek{publicstringthis[intIndex](get{〃注意case段使用return直接返回所以不需要breakswitch(Index)(case0:(return"Todayiscloudy!";)case5:(return"Todayisthundershower!)default:(return"Todayisfine!";))})publicstringthis[stringDay]{getstringTodayWeather=null;//switch的标准写法switch(Day)case"Sunday”:(TodayWeather="Todayiscloudy!";break;)case"Friday":{TodayWeather="Todayisthundershower!";break;)default:(TodayWeather="Todayisfine!";break;))returnTodayWeather;}))classProgram(staticvoidMain(string[]args){Point[]tmpPoints=newPoint[10];for(inti=0;i<tmpPoints.Length;i++){tmpPoints[i]=newPoint(i,Math.Sin(i));}PointstmpObj=newPoints(tmpPoints);for(inti=0;i<tmpObj.PointNumber;i++)(Console.WriteLine(tmpObj[i]);}''Wednesday",string1]Week=newstring!!{"Sunday","Monday","Tuesday","Thursday","Friday","Staurday");''Wednesday",WeatherOfWeektmpWeatherOfWeek=newWeatherOfWeek();for(inti=0;i<6;i++)Console.WriteLine(tmpWeatherOf,Week[i]);}foreach(stringtmpDayinWeek)Console.WriteLine(tmpWeatherOfWeek[tmpDay]);IConsole.ReadLine();))}结果:X:0,Y:0X:1,Y:0.841470984807897X:2,Y:0.909297426825682X:3,Y:0.141120008059867X:4,Y:-0.756802495307928X:5,Y:-0.958924274663138X:6,Y:-0.279415498198926X:7,Y:0.656986598718789X:8,Y:0.989358246623382X:9,Y:0.412118485241757Todayiscloudy!Todayisfine!Todayisfine!Todayisfine!Todayisfine!Todayisthundershower!Todayiscloudy!Todayisfine!Todayisfine!Todayisfine!Todayisfine!Todayisthundershower!Todayisfine!.new修饰符是起什么作用?答:new修饰符与new操作符是两个概念new修饰符用于声明类或类的成员,表示隐藏了基类中同名的成员。而new操作符用于实例化ー个类型new修饰符只能用于继承类,一般用于弥补基类设计的不足new修饰符和override修饰符不可同时用在一个成员上,因为这两个修饰符在含义上互相排斥示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample09(classBaseClass{〃基类设计者声明了一个PI的公共变量,方便进行运算publicstaticdoublePI=3.1415;)classDervieClass:BaseClass(〃继承类发现该变量的值不能满足运算精度,于是可以通过new修饰符显式隐藏基类中的声明publicnewstaticdoublePI=3.1415926;)classProgram(staticvoidMain(string[]args){Console.WriteLine(BaseClass.PI);Console.WriteLine(DervieClass.PI);Console.ReadLine();))}结果:3.14153.1415926.this关键字的含义?答:this是ー个保留字,仅限于构造函数和方法成员中使用在类的构造函数中出现表示对正在构造的对象本身的引用,在类的方法中出现表示对调用该方法的对象的引用,在结构的构造上函数中出现表示对正在构造的结构的引用,在结构的方法中出现表示对调用该方法的结果的引用this保留字不能用于静态成员的实现里,因为这时对象或结构并未实例化在C#系统中,this实际上是ー个常量,所以不能使用this++这样的运算this保留字一般用于限定同名的隐藏成员、将对象本身做为参数、声明索引访问器、判断传入参数的对象是否为本身示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample10(classClassi(privatedoublec;privatestringvalue;publicdoubleC(get{returnc;})publicClassi(doublec){〃限定同名的隐藏成员this.c=c;)publicClassi(Classivalue){〃用对象本身实例化自己没有意义if(this!=value){c=value.C;|)publicoverridestringToStringO(〃将对象本身做为参数returnstring.Format("{0}Celsius={1}Fahrenheit",c,UnitTransClass.C2F(this));1〃由于好奇,在这做了一个效率测试,想看看到底哪种方式访问成员变量更快,结论:区别不大。。。publicstringTest1(){longvTickCount=Environment.TickCount;for(inti=0;i<10000000;i++)this.value=i.lbStringO;returnstring.FormatC'Havethis.:{0}MSEL",Environment.TickCount-vTickCount);)publicstringTest2()(longvTickCount=Environment.TickCount;for(inti=0;i<10000000;i++)value=i.ToString();returnstring.Format("Don'thavethis,:{0}MSEL",Environment.TickCount-vTickCount);))classUnitTransClass(publicstaticdoubleC2F(Classlvalue)(〃摄氏到华氏的转换公式return1.8*value.C+32;))classProgram(staticvoidMain(string[]args){ClassitmpObj=newClassl(37.5);Console.WriteLine(tmpObj);Console.WriteLine(tmpObj.Test1());Console.WriteLine(tmpObj.Test2());Console.ReadLine();))}结果:37.5Celsius=99.5FahrenheitHavethis.:4375MSELDon'thavethis.:4406MSELIL可以使用抽象函数重写基类中的虚函数吗?答:可以需使用new修饰符显式声明,表示隐藏了基类中该函数的实现或增加override修饰符,表示抽象重写了基类中该函数的实现示例:classBaseClass{publicvirtualvoidF(){Console.WrileLine("BaseClass.F");abstractclassDeriveClass1:BaseClass{publicabstractnewvoidF();)〃是他提醒了我还可以用这种方法抽象重写基类的虚方法abstractclassDeriveClass2:BaseClass(publicabstractoverridevoidF();).密封类可以有虚函数吗?答:可以,基类中的虚函数将隐式的转化为非虚函数,但密封类本身不能再增加新的虚函数示例:classBaseClass(publicvirtualvoidF(){Console.WriteLine("BaseClass.F");)sealedclassDeriveClass:BaseClass(〃基类中的虚函数F被隐式的转化为非虚函数〃密封类中不能再声明新的虚函数G//publicvirtualvoidG()//{//Console.WriteLine("DeriveClass.G");//)).什么是属性访问器?答:属性访问器(PropertyAccessor),包括get访问器和set访问器分别用于字段的读写操作其设计目的主要是为了实现面向对象(〇〇)中的封装思想。根据该思想,字段最好设为private,ー个精巧的类最好不要直接把字段设为公有提供给客户调用端直接访问另外要注意属性本身并不一定和字段相联系.abstract可以和virtual一起使用吗?可以和override一起使用吗?答:abstract修饰符不可以和static>virtual修饰符ー起使用abstract修饰符可以和override一起使用,参见第11点示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample14(classBaseClass(publicvirtualvoidF(){Console.WriteLine(nBaseClass.Fn);})abstractclassDeriveClassl:BaseClass(〃在这里,abstract是可以和override一起使用的publicabstractoverridevoidF();)classProgram{staticvoidMain(string[]args).接口可以包含哪些成员?答:接口可以包含属性、方法、索引指示器和事件,但不能包含常量、域、操作符、构造函数和析构函数,而且也不能包含任何静态成员.类和结构的区别?答:类:类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存类有构造和析构函数类可以继承和被继承结构:结构是值类型在栈上分配(虽然栈的访问速度比较堆要快,但栈的资源有限放),结构的赋值将分配产生一个新的对象。结构没有构造函数,但可以添加。结构没有析构函数结构不可以继承自另ー个结构或被继承,但和类ー样可以继承自接口示例:根据以上比较,我们可以得出一些轻量级的对象最好使用结构,但数据量大或有复杂处理逻辑对象最好使用类。如:Geoemtry(GIS里的ー个概论,在OGC标准里有定义)最好使用类,而Geometry中点的成员最好使用结构usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample16(interfaceIPoint{doubleX{get;set;)doubleY{get;set;1doubleZ{get;set;))〃结构也可以从接口继承structPoint:IPointprivatedoublex,y,z;〃结构也可以增加构造函数publicPoint(doubleX,doubleY,doubleZ)this.x=X;this.y=Y;this.z=Z;)publicdoubleX{get{returnx;)set{x=value;})publicdoubleY(get{returnx;}set{x=value;})publicdoubleZ(get{returnx;)set{x=value;}))〃在此简化了点状Geometry的设计,实际产品中还包含Project(坐标变换)等复杂操作classPointGeometry(privatePointvalue;publicPointGeometry(doubleX,doubleY,doubleZ)(value=newPoint(X,Y,Z);)publicPointGeometry(Pointvalue)(〃结构的赋值将分配新的内存this.value=value;)publicdoubleX{get{returnvalue.X;}set{this.value.X=value;)}publicdoubleYget{returnvalue.Y;}set{this.value.Y=value;})publicdoubleZ|get{returnvalue.Z;}set{this.value.Z=value;})publicstaticPointGeometryoperator+(PointGeometryLeft,PointGeometryRigth){returnnewPointGeometry(Left.X+Rigth.X,Left.Y+Rigth.Y,Left.Z+Rigth.Z);}publicoverridestringToStringO{returnstring.Format("X:{0},Y:{1},Z:{2}n,value.X,value.Y,value.Z);))classProgram(staticvoidMain(string[]args)(PointtmpPoint=newPoint(l,2,3);PointGeometrytmpPG1=newPointGeometry(tmpPoint);PointGeometrytmpPG2=newPointGeometry(tmpPoint);tmpPG2.X=4;tmpPG2.Y=5;tmpPG2.Z=6;〃由于结构是值类型,tmpPGl和tmpPG2的坐标并不一样Console.WriteLine(tmpPG1);Console.WriteLine(tmpPG2);〃由于类是引用类型,对tmpPGl坐标修改后影响到了tmpPG3PointGeometrytmpPG3=tmpPGl;tmpPGl.X=7;tmpPGl.Y=8;tmpPGl.Z=9;Console.WriteLine(tmpPG1);Console.WriteLine(tmpPG3);Console.ReadLine();结果:X:1,Y:2,Z:3X:4,Y:5,Z:6X:7,Y:8,Z:9X:7,Y:8,Z:9エフ・接口的多继承会带来哪些问题?答:C#中的接口与类不同,可以使用多继承,即ー个子接口可以有多个父接口。但如果两个父成员具有同名的成员,就产生了二义性(这也正是C・中类取消了多继承的原因之一),这时在实现时最好使用显式的声明示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExamplel7I.classProgram{〃ー个完整的接n声明示例interfacelExample(〃属性stringPget;set;)〃方法stringF(intValue);〃事件eventEventHandlerE;〃索引指示器stringthis[intIndex](get;set;)}interfaceIA{intCount{get;set;}}interfaceIBintCount();)〃IC接口从IA和IB多重继承interfaceIC:IA,IB()classC:IC(privateintcount=100;//显式声明实现IA接口中的Count属性intIA.Count(get{return100;)set{count=value;))〃显式声明实现!B接口中的Count方法intIB.Count()(returncount*count;staticvoidMain(string[]args)CtmpObj=newC();〃调用时也要显式转换Console.WriteLine(""Countproperty:{0}",((IA)tmpObj).Count):Console.WriteLine("Countfunction:{0}",((IB)tmpObj).Count());Console.ReadLine():}))结果:Countproperty:100Countfunction:10000.抽象类和接口的区别?答:抽象类(abstractclass)可以包含功能定义和实现,接口(interface)只能包含功能定义抽象类是从ー系列相关对象中抽象出来的概念,因此反映的是事物的内部共性:接口是为了满足外部调用而定义的ー个功能约定,因此反映的是事物的外部特性分析对象,提炼内部共性形成抽象类,用以表示对象本质,即、、是什么”为外部提供调用或功能需要扩充时优先使用接口

.别名指示符是什么?答:通过别名指示符我们可以为某个类型起・个别名主要用于解决两个命名空间内有同名类型的冲突或避免使用冗余的命名空间别名指示符在所有命名空间最外层定义,作用域为整个单元文件。如果定义在某个命名空间内,那么它只在直接隶属的命名空间内起作用示例:Classi.cs:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespacecom.nblogs.reonlyrun.CSharp25QExample.Examplel9.LibOl(classClassipublicoverridestringToString()

return“com.nblogs.reonlyrun.CSharp25QExample.Examplel9.LibOl*sClassi";}})Class2.cs:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespacecom.nblogs.reonlyrun.CSharp25QExample.Examplel9.Lib02(classClassi(publicoverridestringToString()(return"com.nblogs.reonlyrun.CSharp25QExample.Examplel9.Lib021sClassi";

主单元(Program.cs):usingSystem;usingSystem.Collections.Generic;usingSystem.Text;//使用别名指示符解决同名类型的冲突//在所有命名空间最外层定义,作用域为整个单元文件usingLibOlClassl=com.nblogs.reonlyrun.CSharp25QExample.Examplel9.LibOl.Classl;usingLibO2Class2=com.nblogs.reonlyrun.CSharp25QExample.Examplel9.Lib02.Classl;namespaceExamplel9{namespaceTesti//TestlClass!在Testi命名空间内定义,作用域仅在Test!之

usingTestlClassl=com.nblogs.reonlyrun.CSharp25QExample.Examplel9.LibOl.Classl;classClassi{//LibOlClassl和LibO2class2在这可以正常使用LibOlClassltmpObj1=newLibOlClassl();LibO2Class2tmpObj2=newLibO2Class2();//TestClassl在这可以正常使用TestlClassltmpObj3=newTestlClassl();}}namespaceTest2(usingTestlClass2=com.nblogs.reonlyrun.CSharp25QExample.Examplel9.LibOl.Classl;classProgramstaticvoidMain(string[]args)

//LibOlClassl和LibO2Class2在这可以正常使用LibOlClassltmpObj1=newLibOlClassl();LibO2Class2tmpObj2=newLibO2Class2();〃注意这里,TestClassl在这不可以正常使用。//因为,在Test2命名空间内不能使用Test!命名空间定义的别名//TestlClassltmpObj3=newTestlClassl();//TestClass2在这可以正常使用TestlClass2tmpObj3=newTestlClass2();Console.WriteLine(tmpObj1);Console.WriteLine(tmpObj2);Console.WriteLine(tmpObj3);Console.ReadLine();

结果:com.nblogs.reonlyrun.CSharp25QExampie.Example19.LibOl'sClassicom.nblogs.reonlyrun.CSharp25QExample.Examplel9.Lib02'sClassicom.nblogs.reonlyrun.CSharp25QExample.Examplel9.LibOl'sClassi.如何手工释放资源?答:.NET平台在内存管理方面提供了GC(GarbageCollection),负责自动释放托管资源和内存回收的エ作。但在以下两种情况需要我们手工进行资源释放:ー、由于它无法对非托管资源进行释放,所以我们必须自己提供方法来释放对象内分配的非托管资源,比如你在对象的实现代码中使用了一个COM对象;二、你的类在运行是会产生大量实例(象GIS中的Geometry),必须自己手工释放这些资源以提高程序的运行效率最理想的办法是通过实现ー个接n显式的提供给客户调用端手工释放对象,System命名空间内有一个【Disposable接口,拿来做这事非常合适,省得我们自己再声明一个接口了示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample20

classProgramclassClassi:IDisposable(//析构函数,编译后变成protectedvoidFinalize(),GC会在回收对象前会调用调用该方法-Classi〇(Dispose(false);}//通过实现该接口,客户可以显式地释放对象,而不需要等待GC来释放资源,据说那样会降低效率voidIDisposable.Dispose()(Dispose(true);}//将释放非托管资源设计成一个虚函数,提供在继承类中释放基类的资源的能力protectedvirtualvoidReleaseUnmanageResources()

//Dosomething...//私有函数用以释放非托管资源privatevoidDispose(booldisposing)(ReleaseUnmanageResources();//为true时表示是客户显式调用了释放函数,需通知GC不要再调用对象的Finalize方法//为false时肯定是GC调用了对象的Finalize方法,所以没有必要再告诉GC你不要调用我的Finalize方法啦if(disposing)(GC.SuppressFinalize(this);)})staticvoidMain(string[]args)(//tmpObj!没有手工释放资源,就等着GC来慢慢的释放它吧ClassitmpObj1=newClassi();//tmpObj2调用fDispose方法,传说比等着GC来释放它效率要调ー些//个人认为是因为要逐个对象的查看其元数据,以确认是否实现TDispose方法吧//当然最重要的是我们可以自己确定释放的时间以节省内存,优化程序运行效率ClassitmpObj2=newClassi();((IDisposable)tmpObj2).Dispose();))).P/Invoke是什么?答:在受控代码与非受控代码进行交互时会产生一个事务(transition),这通常发生在使用平台调用服务(PlatformInvocationServices),即P/Invoke如调用系统的AP!或与COM对象打交道,通过System.Runtime.InteropServices命名空间虽然使用Interop非常方便,但据估计每次调用事务都要执行10到40条指令,算起来开销也不少,所以我们要尽量少调用事务如果非用不可,建议本着一次调用执行多个动作,而不是多次调用每次只执行少量动作的原则

22.StringBuilder和String的区别?答:String在进行运算时(如赋值、拼接等)会产生一个新的实例,而StringBuilde「则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用StringBuilder,不要使用String另外,对于String我们不得不多说几句:.它是引用类型,在堆上分配内存.运算时会产生一个新的实例.String对象一旦生成不可改变(Immutable)3.定义相等运算符(==和!=)是为了比较String对象(而不是引用)的值示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample22(classProgram

constintcycle=10000;longvTickCount=Environment.TickCount;Stringstr=null;for(inti=0;i<cycle;i++)str+=i.ToString();Console.WriteLine("String:{0}MSEL”,Environment.TickCount-vTickCount);vTickCount=Environment.TickCount;//看到这个变量名我就生气,奇怪为什么大家都使它呢?:)StringBuiIdersb=newStringBuilder();for(inti=0;i<cycle;i++)sb.Append(i);Console.WriteLine("StringBuilder:{0}MSEL",Environment.TickCount-vTickCount);stringtmpStrl="A";stringtmpStr2=tmpStrl;Console.WriteLine(tmpStrl);Console.WriteLine(tmpStr2);

//注意后面的输出结果,tmpStrl的值改变并未影响到tmpStr2的值tmpStrl="B";Console.WriteLine(tmpStrl);Console.WriteLine(tmpStr2);Console.ReadLine();}))结果:String:375MSELStringBuilder:16MSELAABA.explicit和implicit的含义?答:explicit和implicit属于转换运算符,如用这两者可以让我们自定义的类型支持相互交换explicti表示显式转换,如从A->B必须进行强制类型转换(B=(B)A)

implicit表示隐式转换,如从B->A只需直接赋值(A=B)隐式转换可以让我们的代码看上去更漂亮、更简洁易懂,所以最好多使用implicit运算符。不过!如果对象本身在转换时会损失ー些信息(如精度),那么我们只能使用explicit运算符,以便在编译期就能警告客户调用端示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExample23(classProgram(//本例灵感来源于大话西游经典台词、、神仙?妖怪?”ー主要是我实在想不出什么好例子了classImmortal(publicstringname;publicImmortal(stringName)nameName;

nameName;}publicstaticimplicitoperatorMonster(Immortalvalue)(returnnewMonster(+”:ネ申仙变妖怪?偷偷下凡即可。。。");))classMonster(publicstringname;publicMonster(stringName)(name=Name;}publicstaticexplicitoperatorImmortal(Monstervalue)(returnnewImmortal(+”:妖怪想当ネ申仙?再去修炼五百年!");staticvoidMain(string[]args)Immortaltmplmmortal=newエmmortal(“紫霞仙子”);〃隐式转换MonstertmpObj1=tmplmmortal;Console.WriteLine(tmpO);MonstertmpMonster=newMonster("孙悟空”);//显式转换ImmortaltmpObj2=(Immortal)tmpMonster;Console.WriteLine(tmpO);Console.ReadLine();}))结果:紫霞仙子:神仙变妖怪?偷偷下凡即可。•.孙悟空:妖怪想当神仙?再去修炼五百年!.params有什么用?答:

params关键字在方法成员的参数列表中使用,为该方法提供了参数个数可变的能力它在只能出现一次并且不能在其后再有参数定义,之前可以示例:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceConsoleApplication1(classApp(//第一个参数必须是整型,但后面的参数个数是可变的。//而且由于定的是object数组,所有的数据类型都可以做为参数传入publicstaticvoidUseParams(int

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论