带着问题读CLR via C#(五)类型和成员基础
Q1:类型中可以定义哪些成员?
A1:1)常量;2)字段;3)实例构造函数;4)静态构造函数;5)方法;6)属性;7)事件;8)类型;9)操作符重载;10)转换操作符重载。
Q2:什么是友元程序集,如何创建友元程序集,它的劣势是什么?
A2:程序集A中定义的类型希望程序集B访问,又不希望其他程序集访问,即不能定义为internal或public,此时,可以用友元程序集解决。在构建程序集时,可以使用在System.Runtime.CompilerServices命名空间中定义的一个名为InternalsVisibleTo的特性来标明它认为是“友元”的其他程序集,测试一下:
1)创建一个ClassLibrary,命名为“FriendAssembly”。
2)删除已有类,添加一个类“Test”
1: using System;
2: using System.Runtime.CompilerServices;
3:
4: [assembly:InternalsVisibleTo("FriendAssemblyTest")]
5: namespace FriendAssembly
6: {
7: class Test
8: {
9: public static void Print()
10: {
11: Console.WriteLine("Test");
12: }
13: }
14: }
3)添加一个ConsoleApplication项目,命名为FriendAssemblyTest,添加对FriendAssembly项目的引用,Main方法:
1: namespace FriendAssemblyTest
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: FriendAssembly.Test.Print();
8: }
9: }
10: }
4)运行,发现可以打印出 "Test". 若将一下代码注释掉,则发现FriendAssembly.Test将不能够访问。
[assembly:InternalsVisibleTo("FriendAssemblyTest")]
友元程序集的相互依赖性很高,最好打包到一起发布,若错开太久的发布时间,可能导致兼容性问题。
Q3:访问修饰符有哪些,它们的作用是什么?
A3:1)private,成员只能由定义它的类型或任何嵌套类型中的方法访问;2)protected,成员只能由定义它的类型或任何嵌套类型以及任何程序集内的一个派生类型的方法访问;3)internal,成员只能由定义程序集中的方法访问;4)protected internal,成员可以由任何定义它的类型,嵌套类型,任何程序集内的派生类型中的方法访问;5)public,成员可以由任何程序集中的任何方法访问。
Q4:类的默认修饰符是什么,类成员的默认类型是什么,接口成员的默认修饰符是什么?
A4:类的默认修饰符是internal;类成员的默认类型是private;接口成员的默认修饰符是public,但禁止开发人员显式指定。
Q5:以下代码可否通过编译,为什么?
1: class MyClass
2: {
3: public virtual void TestOne()
4: {
5: }
6:
7: protected virtual void TestTwo()
8: {
9: }
10:
11: internal virtual void TestThree()
12: {
13: }
14: }
15:
16: class MyClassTwo : MyClass
17: {
18: private override void TestOne()
19: {
20: base.TestOne();
21: }
22:
23: public override void TestTwo()
24: {
25: base.TestTwo();
26: }
27:
28: public override void TestThree()
29: {
30: base.TestThree();
31: }
32: }
A5:不可以。一个派生类重写他的基类中定义的成员时,C#编译器要求原始成员可重写成员拥有相同的可访问性。
Q6:什么是静态类?
A6:静态类用来封装一组不与任何对象相关联的方法,如Math类,Console类。静态类不可实例化,不能继承接口,不能包含非静态成员,不能作为字段、方法参数和局部变量使用,只能从System.Object基类继承。
Q7:静态类被编译后,IL中的修饰符是什么?
A7:abstract sealed. 详见如下:
静态类:
1: namespace StaticClass
2: {
3: static class Test
4: {
5: }
6: }
IL:
Q8:何时用分部类、结构和接口?
A8:1)用于源代码控制。如多个开发人员共同写一个类,使用partial关键字标记;2)在同一个文件中,讲一个类或结构分解成不同的逻辑单元。3)代码拆分。如新建一个winform程序,可以发现Form1.cs下,有一个Form1.Designer.cs文件,其中声明了一个partial class Form1,这个类中的代码是自动生成的设计器相关代码,还有一个Form1文件,其中声明了一个继承了Form类的partial class Form1,可以在这个类中编辑自己的代码,这样将代码拆分开来,无论自己的代码如何修改都不会影响设计器的代码。
分部类型完全由C#编译器实现,CLR对分部类型一无所知。