近期开始接触到在校学生、高校实习生和毕业生,在此说一下笔者对这些徘徊在职场门口的学生一些建议,希望能给这些初学者进入软件开发行业带来一些帮助,使得毕业生能更顺利的进入软件开发公司开始职场生涯,人生来一个完美的转弯。
-------------------------------------------------------------------------------
在说明自定义类型是提到了类型以及成员的可访问级别,在此详细说明一下。以下是关于可访问级别的演示代码,这段代码保存在本章配套程序的代码文件“可访问级别.cs”中。
public class 可访问级别范例 { /// <summary> /// 私有成员 /// </summary> private string _PrivateField = null;
/// <summary> /// 受保护的成员 /// </summary> protected string _ProtectedField = null ;
/// <summary> /// 公开的成员 /// </summary> public string _PublicField = null;
/// <summary> /// 程序集内部成员 /// </summary> internal string _InternalField = null;
public void Test() { this._PrivateField = "能访问 private 成员"; this._ProtectedField = "能访问 protected 成员"; this._InternalField = "能访问 internal 成员"; this._PublicField = "能访问 public 成员"; } }
public class 测试可访问级别范例 { public void Test() { 可访问级别范例 instance = new 可访问级别范例( ); instance._InternalField = "能访问 internal 成员"; instance._PublicField = "能访问 public 成员"; // 不能访问 _PrivateField , _InternalField , _ProtectedField } }
public class 测试可访问级别范例2 : 可访问级别范例 { public void Test2() { this._InternalField = "能访问 internal 成员"; this._ProtectedField = "能访问 protected 成员"; this._PublicField = "能访问 public 成员"; //不能访问 this._PrivateField // 如果是在另外一个C#项目中定义了派生类则还不能访问 _InternalField 成员 } } |
使用关键字“private”描述的类型或类型成员是私有的,只能在类型内部访问,超出这个范围就不能访问,派生类型也不能访问基类的私有的成员。例如以下代码就定义了一个私有变量。
private string _PrivateField = null; |
这行代码中,关键字“private”说明这是私有的成员,“string”定义了成员的数据类型,“_PrivateField”为成员的名称,“=null;”定义了该字段的默认值。
使用关键字“protected”描述的类型或类型成员是受保护的,只有类型内部或者从其派生的类型可以访问它,超出这个范围就不能访问了。以下代码就定义了一个收保护的字段。
protected string _ProtectedField = null ; |
使用关键字“internal”描述的类型和类型成员是程序集内部的,只能在程序集内部可见,其效果等价于“public”;而在程序集外部不可见,其效果等价于“private”。例如以下代码就定义了一个内部的字段。
internal string _InternalField = null; |
在VS.NET中,由于一个程序集是由C#工程编译而得,因此程序集内部就等价于C#工程中内部,程序集外部就是引用了该C#工程编译结果的其他C#工程。
比如当C#工程A中定义了一个internal类型,则在工程A中的任意C#代码都能访问这个内部类型;但当C#工程B引用了工程A的编译结果,则在工程B中的任意C#代码都不能访问工程A中定义的内部类型。
使用关键字“public”描述的类型或类型成员是公开的,在任何地方都能访问。以下代码就定义了一个公开的字段。
public string _PublicField = null; |
下表总结了可访问级别
可访问级别 |
类型内部 |
派生的类型 |
同一个程序集的其他类型 |
不同程序集的其他类型 |
public |
可见 |
可见 |
可见 |
可见 |
protected |
可见 |
可见 |
非派生的不可见 |
非派生的不可见 |
Private |
可见 |
不可见 |
不可见 |
不可见 |
internal |
可见 |
同程序集的可见 |
可见 |
不可见 |
类型成员有可访问级别,而类型本身也有可访问级别控制,两者的效果一样。
当类型和类型成员的可访问级别不一致时,从类型外部看,对类型成员的可访问级别是类型的访问级别和类型成员自身的访问级别的叠加,取两者可见范围的交集。
例如当类型是public类型而某个成员方法是internal类型,则在程序集内部该成员方法到处都可见,但在程序集外部不可见。
在定义类型的时候可以指定类型的一些特性,这些样式有
被“static”修饰的类就是静态类型,静态类型其所有的成员都必须标记为静态的,否则会编译错误。静态类型一般用于容纳一些通用的例程,比如某些科学数值运算等。
以下C#代码就定义了一个静态类型
public static class MyStaticClass { public static int Sum(int a, int b) { return a + b; } } |
在代码“public static class MyStaticClass”中,“public”定义类型为公开的,“static”说明该类型是静态的,“class”说明正在定义一个类类型,“MyStaticClass”是类型名称。
在这个类型中定义了一个静态方法Sum,在静态类型中不能定义非静态的成员。由于类型的构造函数也是静态的,因此静态类型不能实例化。
关于静态方法可参考下节。
被“abstract”修饰的类就是抽象类,抽象类是一种介于类和接口之间的类型,定义为抽象类说明其有部分内容尚未实现,有待以后被继承被扩展。以下代码就定义了一个抽象类
public abstract class MyAbstractClass { public abstract int Sum(int a, int b);
public int Div(int a, int b) { return a / b; } } |
在代码“public abstract class MyAbstractClass”中,关键字“abstract”就声明了该类型为抽象类;在代码“public abstract int Sum(int a, int b);”中,关键字“abstract”就声明该成员为抽象成员,抽象成员只能留个定义,不能有任何功能实现代码,因此在这里声明一下Sum方法就用分号结束了定义。
抽象类可以包含不抽象的方法,比如此处包含了一个完整的Div成员方法。。
抽象类不能实例化,对于类型“我的抽象类”,代码“MyAbstractClass instance = new MyAbstractClass( )”是错误的,抽象类必须派生出其他类型才能使用;而且派生的时候,所有的抽象成员必须强制被重写。由于抽象类必须被重载,因此抽象类不能是密封类,也就是说关键字“abstract”和“sealed”是相互排斥的。
以下代码就从抽象类“MyAbstractClass”派生新的类型
public class MyClassFromMyAbstractClass : MyAbstractClass { public override int Sum(int a, int b) { return a + b; } } |
由于从抽象类派生新类型时,开发人员可能忘记抽象类中定义的抽象成员,此时VS.NET的C#代码编辑器提供帮助功能,这个和帮助生成实现接口的功能类型,如下图所示
当文本光标移动到方框处的“MyAbstractClass”,则左下角出现一个智能标签,鼠标点击这个智能标签会弹出一个菜单,点击菜单项目“实现抽象类“MyAbstractClass””就会自动生成以下代码。
public class MyClassFromMyAbstractClass : MyAbstractClass { public override int Sum(int a, int b) { throw new NotImplementedException(); } } |
这个时候开发人员就可以往重载的成员中添加功能代码了。
由于抽象类型不能实例化,因此必须借助它的派生类型才能使用,比如以下的代码
MyAbstractClass instance = new MyClassFromMyAbstractClass(); instance.Div(1, 2); instance.Sum(3, 4); |
当然派生类型可以独立使用,如以下代码
MyClassFromMyAbstractClass instance2 = new MyClassFromMyAbstractClass(); instance2.Div(1, 2); instance2.Sum(3, 4); |
被关键字“sealed”修饰的类是密封类,密封类可以继承自其它类,但不能被继承,不能包含虚方法和抽象方法。以下代码就定义了一个密封类
public sealed class MySealedClass { public int Sum(int a, int b) { return a + b; } } |
由于密封类不能被继承,不能被扩展,这可能会影响系统的扩展性,因此慎用,在实际中用得比较少。