当初学C#时是找个人大概问了一下数据类型和分支语句就开始做项目了。这两天又全面的看了一下相关的基础知识(学而时习之嘛),总结了25个问题: 1.静态成员和非静态成员的区别?2.const和staticreadonly区别?3.extern是什么意思?4.abstract是什么意思?5.internal修饰符起什么作用?6.sealed修饰符是干什么的?7.override和overload的区别?8.什么是索引指示器?9.new修饰符是起什么作用?10.this关键字的含义?11.可以使用抽象函数重写基类中的虚函数吗?12.密封类可以有虚函数吗?13.什么是属性访问器?14.abstract可以和virtual一起使用吗?可以和override一起使用吗?15.接口可以包含哪些成员?16.类和结构的区别?17.接口的多继承会带来哪些问题?18.抽象类和接口的区别?19.别名指示符是什么?20.如何手工释放资源?21.P/Invoke是什么?22.StringBuilder和String的区别?23.explicit和implicit的含义?24.params有什么用?25.什么是反射? 以下是我做的一份参考答案(C#语言范畴之内),如果有不准确、不全面的,欢迎各位朋友指正! 1.静态成员和非静态成员的区别? 答: 静态变量使用static修饰符进行声明,在类被实例化时创建,通过类进行访问 不带有static修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问 一个类的所有实例的同一静态变量都是同一个值,同一个类的不同实例的同一非静态变量可以是不同的值 静态函数的实现里不能使用非静态成员,如非静态变量、非静态函数等 示例: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceExample01 { classProgram { classClass1 { publicstaticStringstaticStr=Class; publicStringnotstaticStr=Obj; } staticvoidMain(string[]args) { //静态变量通过类进行访问,该类所有实例的同一静态变量都是同一个值 Console.WriteLine(Class1sstaticStr:{0},Class1.staticStr); Class1tmpObj1=newClass1(); tmpObj1.notstaticStr=tmpObj1; Class1tmpObj2=newClass1(); tmpObj2.notstaticStr=tmpObj2; //非静态变量通过对象进行访问,不同对象的同一非静态变量可以有不同的值 Console.WriteLine(tmpObj1snotstaticStr:{0},tmpObj1.notstaticStr); Console.WriteLine(tmpObj2snotstaticStr:{0},tmpObj2.notstaticStr); Console.ReadLine(); } } } 结果:Class1sstaticStr:ClasstmpObj1snotstaticStr:tmpObj1tmpObj2snotstaticStr:tmpObj2 2.const和staticreadonly区别? 答: const 用const修饰符声明的成员叫常量,是在编译期初始化并嵌入到客户端程序 staticreadonly 用staticreadonly修饰符声明的成员依然是变量,只不过具有和常量类似的使用方法:通过类进行访问、初始化后不可以修改。但与常量不同的是这种变量是在运行期初始化 示例: 测试类: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceExample02Lib { publicclassClass1 { publicconstStringstrConst=Const; publicstaticreadonlyStringstrStaticReadonly=StaticReadonly; //publicconstStringstrConst=ConstChanged; //publicstaticreadonlyStringstrStaticReadonly=StaticReadonlyChanged; } } 客户端代码: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; usingExample02Lib; namespaceExample02 { classProgram { staticvoidMain(string[]args) { //修改Example02中Class1的strConst初始值后,只编译Example02Lib项目 //然后到资源管理器里把新编译的Example02Lib.dll拷贝Example02.exe所在的目录,执行Example02.exe //切不可在IDE里直接调试运行因为这会重新编译整个解决方案!! //可以看到strConst的输出没有改变,而strStaticReadonly的输出已经改变 //表明Const变量是在编译期初始化并嵌入到客户端程序,而StaticReadonly是在运行时初始化的 Console.WriteLine(strConst:{0},Class1.strConst); Console.WriteLine(strStaticReadonly:{0},Class1.strStaticReadonly); Console.ReadLine(); } } } 结果:strConst:ConststrStaticReadonly:StaticReadonly 修改后的示例: 测试类: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceExample02Lib { publicclassClass1 { //publicconstStringstrConst=Const; //publicstaticreadonlyStringstrStaticReadonly=StaticReadonly; publicconstStringstrConst=ConstChanged; publicstaticreadonlyStringstrStaticReadonly=StaticReadonlyChanged; } } 结果 strConst:ConststrStaticReadonly:StaticReadonlyChanged 3.extern是什么意思? 答: extern修饰符用于声明由程序集外部实现的成员函数 经常用于系统API函数的调用(通过DllImport)。注意,和DllImport一起使用时要加上static修饰符 也可以用于对于同一程序集不同版本组件的调用(用extern声明别名) 不能与abstract修饰符同时使用 示例: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; usingSystem.Runtime.InteropServices; namespaceExample03 { classProgram { //注意DllImport是一个AttributeProperty,在System.Runtime.InteropServices命名空间中定义 //extern与DllImport一起使用时必须再加上一个static修饰符 [DllImport(User32.dll)] publicstaticexternintMessageBox(intHandle,stringMessage,stringCaption,intType); staticintMain() { stringmyString; Console.Write(Enteryourmessage:); myString=Console.ReadLine(); returnMessageBox(0,myString,MyMessageBox,0); } } } 结果: 4.abstract是什么意思? 答: abstract修饰符可以用于类、方法、属性、事件和索引指示器(indexer),表示其为抽象成员 abstract不可以和static、virtual一起使用 声明为abstract成员可以不包括实现代码,但只要类中还有未实现的抽象成员(即抽象类),那么它的对象就不能被实例化,通常用于强制继承类必须实现某一成员 示例: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceExample04 { #region基类,抽象类 publicabstractclassBaseClass { //抽象属性,同时具有get和set访问器表示继承类必须将该属性实现为可读写 publicabstractStringAttribute { get; set; } //抽象方法,传入一个字符串参数无返回值 publicabstractvoidFunction(Stringvalue); //抽象事件,类型为系统预定义的代理(delegate):EventHandler publicabstracteventEventHandlerEvent; //抽象索引指示器,只具有get访问器表示继承类必须将该索引指示器实现为只读 publicabstractCharthis[intIndex] { get; } } #endregion #region继承类 publicclassDeriveClass:BaseClass { privateStringattribute; publicoverrideStringAttribute { get { returnattribute; } set { attribute=value; } } publicoverridevoidFunction(Stringvalue) { attribute=value; if(Event!=null) { Event(this,newEventArgs()); } } publicoverrideeventEventHandlerEvent; publicoverrideCharthis[intIndex] { get { returnattribute[Index]; } } } #endregion classProgram { staticvoidOnFunction(objectsender,EventArgse) { for(inti=0;i((DeriveClass)sender).Attribute.Length;i++) { Console.WriteLine(((DeriveClass)sender)[i]); } } staticvoidMain(string[]args) { DeriveClasstmpObj=newDeriveClass(); tmpObj.Attribute=; Console.WriteLine(tmpObj.Attribute); //将静态函数OnFunction与tmpObj对象的Event事件进行关联 tmpObj.Event+=newEventHandler(OnFunction); tmpObj.Function(); Console.ReadLine(); } } } 结果: 5.internal修饰符起什么作用? 答: internal修饰符可以用于类型或成员,使用该修饰符声明的类型或成员只能在同一程集内访问 接口的成员不能使用internal修饰符 值得注意的是,如果为internal成员加上了protected修饰符,这时的访问级别为internal或protected。只是看字面意思容易弄错,许多人认为internalprotected应该是“只有同一个程序集中的子类可以访问”,但其实它表示“同一个程序集中的所有类,以及所有程序集中的子类都可以访问” 示例 Example05Lib项目的Class1 usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceExample05Lib { publicclassClass1 { internalStringstrInternal=null; publicStringstrPublic; internalprotectedStringstrInternalProtected=null; } } 结果Example05Lib项目的Class2类可以访问到Class1的strInternal成员,当然也可以访问到strInternalProtected成员,因为他们在同一个程序集里 Example05项目里的Class3类无法访问到Class1的strInternal成员,因为它们不在同一个程序集里。但却可以访问到strInternalProtected成员,因为Class3是Class1的继承类 Example05项目的Program类既无法访问到Class1的strInternal成员,也无法访问到strInternalProtected成员,因为它们既不在同一个程序集里也不存在继承关系 6.sealed修饰符是干什么的? 答: sealed修饰符表示密封 用于类时,表示该类不能再被继承,不能和abstract同时使用,因为这两个修饰符在含义上互相排斥 用于方法和属性时,表示该方法或属性不能再被重写,必须和override关键字一起使用,因为使用sealed修饰符的方法或属性肯定是基类中相应的虚成员 通常用于实现第三方类库时不想被客户端继承,或用于没有必要再继承的类以防止滥用继承造成层次结构体系混乱 恰当的利用sealed修饰符也可以提高一定的运行效率,因为不用考虑继承类会重写该成员 示例: usingSystem; usingSystem.Collections.Generic; usingSystem.Text; namespaceExample06 { classProgram { classA { publicvirtualvoidF() { Console.WriteLine(A.F); } publicvirtualvoidG() { Console.WriteLine(A.G); } } classB:A { publicsealedoverridevoidF() { Console.WriteLine(B.F); } publicoverridevoidG() { Console.WriteLine(B.G); } } classC:B { publicoverridevoidG() { Console.WriteLine(C.G); } } staticvoidMain(string[]args) { newA().F(); newA().G(); newB().F(); newB().G(); newC().F(); newC().G(); Console.ReadLine(); } } } 结果:类B在继承类A时可以重写两个虚函数,如图所示: 由于类B中对F方法进行了密封,类C在继承类B时只能重写一个函数,如图所示: 控制台输出结果,类C的方法F只能是输出类B中对该方法的实现: A.FA.GB.FB.GB.FC.G 7.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(DeriveClass.F); } publicvoidAdd(intLeft,intRight) { Console.WriteLine(AddforInt:{0},Left+Right); } publicvoidAdd(doubleLeft,doubleRight) { Console.WriteLine(Addforint:{0},Left+Right); } } staticvoidMain(string[]args) { DeriveClasstmpObj=newDeriveClass(); tmpObj.F(); tmpObj.Add(1,2); tmpObj.Add(1.1,2.2); Console.ReadLine(); } } } 结果:BaseClass.FDeriveClass.FAddforInt:3Addforint:3.3 白癜风怎么治中医治白癜风转载请注明原文网址:http://www.helimiaopu.com/cxfz/1184.html |