7. 构造函数的执行
初始化类的静态成员和实例成员。继承层次链中的每个类在执行它自己的构造函数之前都执行它的基类构造函数。
构造函数的初始化语句
默认情况,在构造对象时,将调用基类的无参数构造函数。构造函数可以重载,所以基类构造函数可能有多个。
使用关键字base并指明使用哪一个基类构造函数
使用关键字this并指明应该使用当前类的哪一个构造函数。
public MyDerivedClass(int x,string s):base(x, s) // 关键字base ,显示使用基类构造函数
public MyClass(int x) : this(x) // 关键字 this,减少重复代码,
示例代码如下:
class MyClass
{
readonly int Field1;
readonly double Field2;
public string UserName;
public int UserId;
private MyClass()// 私有构造函数,公共的初始化
{
Field1 = 10;
Field2 = 6.6;
}
public MyClass(string name):this()
{
UserName = name;
UserId = -1;
}
public MyClass(int id) : this()
{
UserName = “Anonymouse”;
UserId = id;
}
}
类的访问修饰符
类可以被系统中其它类看到并访问。
可访问的也称为可见的。
标记public 的类是可被系统内任何程序集中的代码访问。
标记internal的类只能被它自己所在的程序集内的类可见。程序集外的代码不能访问该类。
8. 程序集间的继承
C#也允许从一个在不同程序集内定义的基类来派生类。
基类必须是public, 必须引用包含基类的程序集
using BaseClassNameSpace; 包含基类声明的命名空间,基类要声明为共有,使之对程序集外部可见
9. 成员访问修饰符
5个成员访问级别:
public
private
protected
internal
protected internal
如果不对某个成员指定访问级别,它隐式为private; 成员的可访问性不能比它的类高。
访问成员的区域
类通过成员的访问修饰符指明了哪些成员可以被其它类访问。
共有成员的可访问性
public访问级别是限制最少的,所有类,包含程序集内部的类和外部的类都可以访问。
私有成员的可访问性
private 访问级别是限制最严格的,只能是自己的类访问,不能被其它类访问。
受保护成员的可访问性
protected访问级别如同 private 访问级别,但它允许派生自该类的类访问该成员。
内部成员的可访问性
标记 internal 的成员对程序集内部的所有类都是可见的,但是对程序集外部的类不可见。
受保护的内部成员的可访问性
标记 protected internal 的成员对所有继承类的类以及程序集内部的所有类可见。
是protected 和 internal 的并集,不是交集
总结:
private 只在类的内部可访问
internal 对该程序集内部所有类可访问
protected 对所有继承自该类的类可访问
protected internal 对所有继承该类或在该程序集内部声明的类可访问
public 对任何类可访问
10. 抽象成员
抽象成员是指设计为被重载的成员函数,有如下特征:
必须是一个函数,字段和常量不能定义为抽象成员
必须使用 abstract修饰符标记
不能有实现代码块
抽象成员只能出现在抽象类中,一共有4中类型成员可声明为抽象:
方法,属性,事件,索引器
抽象成员必须在派生类中重写,但不能使用virtual 修饰符
派生类中实现抽象成员,必须指定override修饰符
虚成员和抽象成员的区别:vritual 有实现体, abstract没有实现体,分号取代
abstract class MyDemo
{
abstract public void Print(string s);
abstract public int MyProperty
{
get;//分号替换实现
set;
}
}
11. 抽象类
抽象类是指设计为被继承的类。抽象类只能被用作其它类的基类。
不能创建抽象类的实例。
抽象类可以包含抽象成员或普通非抽象成员。
抽象类可以派生自另一个抽象类。
任何派生自抽象类的类必须使用override 关键字实现该类所有的抽象成员,除非派生类也是抽象类
abstract class MyDemo //抽象类
{
public void Print()//普通方法
{
Console.WriteLine(“I am Base class”);
}
abstract public void MyAbstract();//抽象方法
}
class DerivedClass : MyDemo //派生类
{
public override void MyAbstract()//抽象方法的实现
{
Console.WriteLine(“I am Derived class”);
}
}
测试:
class Program
{
static void Main(string[] args)
{
DerivedClass d = new DerivedClass();
d.Print();//调用继承方法
d.MyAbstract();// 调用抽象方法
}
}
输出:
I am Base class
I am Derived class
测试抽象类2:
abstract class MyBase //抽象和非抽象成员的组合
{
public int w = 10;
const int count = 3;// 数据成员
abstract public void PrintNumber(string s);//抽象方法
abstract public int MyProperty { get; set; }//抽象属性
public int CountValue()//普通方法
{
return count * w;
}
}
class DClass : MyBase
{
private int _myValue;
public override int MyProperty
{
get => _myValue;
set => _myValue=value;
}
public override void PrintNumber(string s)//覆盖抽象方法
{
Console.WriteLine(s);
}
}
测试如下:
class Program
{
static void Main(string[] args)
{
DClass dc = new DClass();
dc.PrintNumber(“This is a string”);
dc.MyProperty = 28;
Console.WriteLine(dc.MyProperty);
Console.WriteLine($"{dc.CountValue()}");
}
}
输出:
This is a string
28
30
12. 密封类
密封类只能被用作独立的类,不能被用作基类。使用sealed修饰符标注。
13. 静态类
静态类中的所有成员都是静态的。
使用static 标记
类所有成员必须是静态的
类可以有一个静态构造函数,不能有实例构造函数
静态类是隐式密封的,即不能被继承。
创建静态类:
static class MyClass
{
public static float PI = 3.14f;
public static bool isOdd(int x)
{
return x % 2 == 1;
}
public static int doubleTimes(int x)
{
return 2 * x;
}
}
测试:
class Program
{
static void Main(string[] args)
{
int x = 5;
Console.WriteLine($“5 is odd :{MyClass.isOdd(x)}”);
Console.WriteLine($“5 * 2 is {MyClass.doubleTimes(x)}”);
}
}
输出:
5 is odd :True
5 * 2 is 10
14. 扩展方法
我们所看到的方法都和声明它的类关联的,扩展方法特性扩展了这个边界,允许编写的方法和声明它的类之外的类关联。
如果有类的源码,当然可直接添加新方法。如果不能修改这个类,只有不是密封的,就可以把它做记录,在派生类中实现新方法。然而,如果不能访问代码,或类是密封的,或其它设计原因,使用这些方法都适应,就不得不在另一个使用该类的共有成员的类中编写一个方法。
定义类:
class MyData
{
private double d1;
private double d2;
private double d3;
public MyData(double D1,double D2, double D3)
{
d1 = D1;
d2 = D2;
d3 = D3;
}
public double Sum()
{
return d1 + d2 + d3;
}
}
定义扩展方法:
static class ExtendMyData //扩展方法,必须是静态的
{
public static double Average (this MyData md)
{
return md.Sum() / 3;
}
}
测试代码:
class Program
{
static void Main(string[] args)
{
MyData md = new MyData(3, 4, 5);
Console.WriteLine($“Average {ExtendMyData.Average(md)}”);
}
}
输出:
Average 4
扩展方法:
扩展方法的类必须声明为静态 static
扩展方法本身必须声明为static
扩展方法必须包含关键字this,作为它的第一个参数类型,并在后面跟着它扩展的类的名称。
15. 命名的约定
类的名称,变量的名称,方法的名称,属性的名称
常用命名风格:
Pascal 大小写 :标识符中的每个单词的首字母大写
Camel 大小写: 标识符中的每个单词首字母代写,第一个单词除外
下划线加Camel大小写: 以下划线开头的Camel大小写的标识符
并不是所有人认同这些命名约定,特别是前缀下划线。尽量使用精准的,自描述的变量名称。