|
@@ -0,0 +1,160 @@
|
|
1
|
+> 继承的类型
|
|
2
|
+- 单重继承:表示一个类可以派生自一个基类。C#就采用这种继承。
|
|
3
|
+- 多重继承:多重继承允许一个类派生自多个类。C#不支持类的多重继承,但允许接口的多重继承。
|
|
4
|
+- 多层继承:多层继承允许继承有更大的层次结构。类B派生自类A。类C又派生自类B。其中,类B也称为中间基类,C#支持它,也很常用
|
|
5
|
+- 接口继承:定义了接口的继承。这里允许多重继承。
|
|
6
|
+
|
|
7
|
+>实现继承
|
|
8
|
+- 声明派生自另一个类的一个类,可以用下列语法:
|
|
9
|
+```
|
|
10
|
+class MyDerivedClass:MyBaseClass
|
|
11
|
+{
|
|
12
|
+ //
|
|
13
|
+}
|
|
14
|
+```
|
|
15
|
+- 如果类也派生自接口,则用逗号分隔列表中的基类和接口:
|
|
16
|
+```
|
|
17
|
+public class MyDerivedClass:MyBaseClass,IInterfacel,IInterface2
|
|
18
|
+{
|
|
19
|
+ //
|
|
20
|
+}
|
|
21
|
+
|
|
22
|
+```
|
|
23
|
+- 如果类和接口都用于派生,则类总是必须放在接口的前面。
|
|
24
|
+- 对于结构,语法如下(只能用于接口继承):
|
|
25
|
+```
|
|
26
|
+public struct MyDerivedStruct:IInterfacel,IInterface2
|
|
27
|
+{
|
|
28
|
+ //
|
|
29
|
+}
|
|
30
|
+```
|
|
31
|
+- 如果在类定义中没有指定的基类,C#编译器就假定System.Object 是基类。因此,派生自Object类(或使用object关键字),与不定义基类的效果是相同的。
|
|
32
|
+```
|
|
33
|
+class MyClass //implicitly derives from System.Object
|
|
34
|
+{
|
|
35
|
+
|
|
36
|
+}
|
|
37
|
+```
|
|
38
|
+举个例子,无论是矩形还是椭圆,形状都有一些共同点;形状都有位置和大小。定义相应的类时,位置和大小应包含在Shape类中。Shape类定义了只读属性Position和Shape,它们使用自动属性初始化器来初始化
|
|
39
|
+```
|
|
40
|
+public class Position
|
|
41
|
+{
|
|
42
|
+ public int X{get;set;}
|
|
43
|
+ public int Y{get;set;}
|
|
44
|
+}
|
|
45
|
+public class Size
|
|
46
|
+{
|
|
47
|
+ public int Width{get;set;}
|
|
48
|
+ public int Heigh{get;set;}
|
|
49
|
+}
|
|
50
|
+public class Shape
|
|
51
|
+{
|
|
52
|
+ public Position Position{get;}=new Position();
|
|
53
|
+ public Size Size{get;}=new Size();
|
|
54
|
+}
|
|
55
|
+```
|
|
56
|
+
|
|
57
|
+> 虚方法
|
|
58
|
+- 把一个基类方发声明为virtual,就可以在任何派生类中重写该方法
|
|
59
|
+```
|
|
60
|
+public class Shape
|
|
61
|
+{
|
|
62
|
+ public virtual void Draw()
|
|
63
|
+ {
|
|
64
|
+ WriteLine($"Shape with {Position}and{size}");
|
|
65
|
+ }
|
|
66
|
+}
|
|
67
|
+```
|
|
68
|
+- 也可以把virtual 关键字和表达式体的方法(使用Lamda运算符)一起使用。这个语法可以独立修饰符,单独使用
|
|
69
|
+```
|
|
70
|
+public class Shape
|
|
71
|
+{
|
|
72
|
+ public virtual void Draw()=>WriteLine($"Shape with {Position}and{size}")
|
|
73
|
+}
|
|
74
|
+```
|
|
75
|
+- 也可以把属性声明为virtual。对于虚属性或重写属性,语法与非虚属性相同,但要在定义中添加关键字virtual,其语法如下
|
|
76
|
+```
|
|
77
|
+public virtual Size Size{get;set;}
|
|
78
|
+可以给虚属性使用完整的属性语法:
|
|
79
|
+private Size _size;
|
|
80
|
+public virtual Size Size
|
|
81
|
+{
|
|
82
|
+ get
|
|
83
|
+ {
|
|
84
|
+ return _size;
|
|
85
|
+ }
|
|
86
|
+ set
|
|
87
|
+ {
|
|
88
|
+ _size=value;
|
|
89
|
+ }
|
|
90
|
+}
|
|
91
|
+```
|
|
92
|
+- Size和Position类型重写了ToString()方法。这个方法在基类Object中声明virtual:
|
|
93
|
+```
|
|
94
|
+public class Position
|
|
95
|
+{
|
|
96
|
+ public int X{get;set;}
|
|
97
|
+ public int Y{get;set;}
|
|
98
|
+ public override string ToString()=>$"X:{X},Y:{Y}";
|
|
99
|
+}
|
|
100
|
+public class Size
|
|
101
|
+{
|
|
102
|
+ public int Width{get;set;}
|
|
103
|
+ public int Height{get;set;}
|
|
104
|
+ public override string ToString()=>$"Width:{Width},Height:{Height}";
|
|
105
|
+}
|
|
106
|
+```
|
|
107
|
+
|
|
108
|
+> is和as运算符
|
|
109
|
+- is和as是与继承有关的重要运算符
|
|
110
|
+
|
|
111
|
+> using
|
|
112
|
+- using关键字在C#中用多个用法,using声明用于导入名称空间。using语句处理实现IDisposable的对象,并在作用域的末尾用Dispose方法。
|
|
113
|
+
|
|
114
|
+> 实现IDisposable接口和析构函数
|
|
115
|
+- 利用运行库强制执行的析构函数,但析构函数的执行是不确定的,而且,由于垃圾回收器的工作方式,它会给运行库增加不可接受的系统开销。
|
|
116
|
+- IDisposable 接口提供一种机制,该机制允许类的用户控制释放资源的时间,但需要确保调用Dispose()方法。
|
|
117
|
+- 如果创建了终结器,就应该实现IDisposable接口。
|
|
118
|
+- 双重实现的例子
|
|
119
|
+```
|
|
120
|
+using System;
|
|
121
|
+public class ResourceHolder:IDisposable
|
|
122
|
+{
|
|
123
|
+ private bool _isDisposed=false;
|
|
124
|
+ public void Dispose()
|
|
125
|
+ {
|
|
126
|
+ Dispose(true);
|
|
127
|
+ GC.SuppressFinalize(this);
|
|
128
|
+ }
|
|
129
|
+ protect virtual void Dispose(bool disposing)
|
|
130
|
+ {
|
|
131
|
+ if(!_isDisposed)
|
|
132
|
+ {
|
|
133
|
+ if(disposing)
|
|
134
|
+ {
|
|
135
|
+
|
|
136
|
+ }
|
|
137
|
+ }
|
|
138
|
+ }
|
|
139
|
+ _isDisposed=true;
|
|
140
|
+}
|
|
141
|
+-ResourceHolder()
|
|
142
|
+{
|
|
143
|
+ Dispose(false);
|
|
144
|
+}
|
|
145
|
+public void SomeMethod()
|
|
146
|
+{
|
|
147
|
+ if(_isDisposed)
|
|
148
|
+ {
|
|
149
|
+ throw new ObjectDisposedException("ResourceHolder");
|
|
150
|
+ }
|
|
151
|
+}
|
|
152
|
+Dispose()方法有第二个protect的重载方法,它带一个布尔参数,这是真正完成清理工作的方法。Dispose(bool)方法由析构函数和IDisposable.Dispose()方法调用。
|
|
153
|
+```
|
|
154
|
+
|
|
155
|
+>IDisposable和终结器的规则
|
|
156
|
+- 如果类定义了实现IDisposable的成员,该类也应该实现IDisposable
|
|
157
|
+- 实现IDisposable并不意味着也应该实现一个终结器。终结器会带来额外的开销,因为它需要创建一个对象,释放该对象的内存,需要GC的额外处理。只在需要时才应该实现终结器,例如,发布本机资源。要释放本机资源,就需要终结器
|
|
158
|
+- 如果实现了终结器,也应该实现IDisposable接口。这样,本机资源可以早些释放,而不仅实在GC找出被占用的资源时,才释放资源。
|
|
159
|
+- 在终结器的实现代码中,不能访问已终结的对象。终结器的执行顺序是没有保证的
|
|
160
|
+- 如果所使用的一个对象实现了IDisposable接口,就不再需要对象时调用Dispose方法。如果在方法中使用这个对象,using语句比较方便。如果对象是类的一个成员,就让类也实现IDisPOSable。
|