1 11..Net面向对象编程
2 a.面向对象的含义:1).字段和属性
3 字段:类中的变量(类内部用的存储数据)
4 属性:类提供给外部调用的类存储的数据 可以使用 对象.属性 设置或读取 一个值
5 get{reture xxx;}表示可读
6 set{xxx = value;}表示可写
7 2).析构函数
8 .Net Framework使用析构函数清理对象
9 使用~前缀的类名(与构造函数的相同)来声明
10 public class MyClass
11 {
12 ~MyClass()
13 {
14 //函数体
15 }
16 }
17 3).静态static
18 静态构造函数:不能有访问修饰符,不能带任何参数静态构造函数不能直接调用,只能在
19 以下情况调用:
20 创建包含静态构造函数的类实例时
21 访问包含静态构造函数的类的静态成员时
22 静态类:只包含静态成员,不能实例化对象,不能有实例构造函数,可以有静态构造函数
23 b.OOP技术:1).类可密封(seal),密封的类不能用作基类
24 2).接口可以继承其他接口,与类不同的是,接口可继承多个基接口
25 3).接口的多态性:接口不能像类那样实例化对象,但可以建立接口类型的变量然后可以在支持
26 该接口的对象上,使用该对象访问接口提供的方法和属性
27 4).对象间的关系:
28 包含关系:一个类包含另一个类。
29 用一个成员字段包含对象实例,该实例可以是公共字段,
30 集合关系:一个类用作另一个类多个实例的容器。集合包括索引、排序和重置大小等功能
31 通常有一个Item属性,它根据对象的索引返回该对象
32 Animal[] animals = new Animal[5];
33
34 12.C#中的类定义
35 a.访问修饰符:无或internal 只能在当前项目中访问类
36 public 可以在任何地方访问类
37 abstract或internal abstract 类只能在当前项目中访问,不能实例化,只能继承
38 public abstract 类可以在任何地方访问,不能实例化,只能继承
39 sealed或internal sealed 类只能在当前项目中访问,不能派生,只能实例化
40 public sealed 类可以在任何地方访问,不能派生,只能实例化
41 b.类、接口:类继承:
42 public class MyClass : MyBase
43 {
44 //类成员
45 }
46 接口的实现:
47 public class MyClass : IMyInterface , IMySecondInterface
48 {
49 //类成员
50 }
51 不能在接口中使用关键字abstract和sealed,因为这两个修饰符在接口定义中 是没有意义的
52 (他们不包含实现代码,所以不能直接实例化,且必须是可以继承的)
53 接口没有继承System.Object.可以使用接口类型的变量来访问System.Object的成员
54 c.构造函数的执行循序:
55 public class MyBaseClass
56 {
57 public MyBaseClass()
58 {}
59 public MyBaseClass(int i)
60 {}
61 }
62
63 public class MyDerivedClass : MyBaseClass
64 {
65 public MyDerivedClass()
66 {}
67 public MyDerivedClass(int i)
68 {}
69 public MyDerivedClass(int i, int j)
70 {}
71 }
72 MyDerivedClass类实例化构造函数执行循序:
73 System.Object.Object()构造函数
74 MyBaseClass.MyBaseClass()构造函数
75 MyDerivedClass.MyDerivedClass()构造函数
76
77 public class MyDerivedClass : MyBaseClass
78 {
79 ...
80
81 public MyDerivedClass(int i, int j) : base(i)
82 {}
83 }
84 base关键字指定.NET实例化过程使用基类中有指定参数的构造函数
85 也可使用该关键字指定基类构造函数的字面值
86 public class MyDerivedClass : MyBaseClass
87 {
88 public MyDerivedClass() : base(5)
89 {}
90 ...
91 }
92
93 this关键字,指定在调用指定的构造函数前,对当前类实例化使用非默认的构造函数
94 public class MyDerivedClass : MyBaseClass
95 {
96 public MyDerivedClass() : this(5, 6)
97 {}
98
99 ...
100
101 public MyDerivedClass(int i, int j) : base(i)
102 {}
103 }
104 构造函数执行序列:
105 System.Object.Object()构造函数
106 MyBaseClass.MyBaseClass(int i)构造函数
107 MyDerivedClass.MyDerivedClass(int i, int j)构造函数
108 MyDerivedClass.MyDerivedClass()构造函数
109
110 d.结构和类
111 结构和类非常相似,但结构是值类型,类是引用类型
112 namespace Test
113 {
114 class MyClass
115 {
116 public int val;
117 }
118 struct myStruct
119 {
120 public int val;
121 }
122 class Program
123 {
124 MyClass objectA = new MyClass();
125 MyClass objectB = objectA;
126 objectA.val = 10;
127 objectB.val = 20;
128 myStruct structA = new myStruct();
129 myStruct structB = structA;
130 structA.val = 30;
131 structB.val = 40;
132 Console.WriteLine("objectA.val = {0}", objectA.val);
133 Console.WriteLine("objectB.val = {0}", objectB.val);
134 Console.WriteLine("structA.val = {0}", structA.val);
135 Console.WriteLine("structB.val = {0}", structB.val);
136 Console.ReadKey();
137 }
138 }
139 结果:objectA.val = 20, objectB.val = 20, structA.val = 30, structB.val = 40
140 e.浅度复制和深度复制
141 利用受保护的方法System.Object.MemberwiseClone()可以进行浅度复制,也就是说对于含有引用类型字段
142 的对象来说,进行浅度复制意味着复制的对象和源对象存在这相同的引用。如果源对象的引用变量的值发生改变,
143 那么被复制的对象的成员值也会发生变化。
144 有很多适合这都不是我们希望看到的结果, 所以有必要对对象进行深度复制,这可以通过ICloneable接口
145 的Clone方法实现,它通过创建新对象的方法进行深度复制。在比较复杂的对象系统调用Clone()是一个递归
146 的过程,这次复制的对象和源对象是独立的。
147
148 浅度复制对引用类型只复制引用,及复制后源引用与目标引用的引用类型是指向都一个对象,操作其中一个,
149 另外一个也会受影响;深度复制则源引用和目标引用对 象的是两个不同的对象,操作互不影响;浅度复制是
150 直接完全把栈的内容拷贝一份而已,而深度复制把对应的堆内容也拷贝了一份;浅度复制可以直接
151 调用 System.Object.MemberwiseClone()这个受保护的方法就可以了;而深度引用根据C#的规范实现ICloneable
152 接口即可。
153
154 首先给出第一个使用System.Object.MemberwiseClone()实现浅度复制的实例,在Cloner中,
155 我们只定义了值类型的成员变量Val:
156 public class Cloner {
157 public int Val;
158 public Cloner(int newVal) {
159 Val = newVal;
160 }
161
162 public object GetCopy() {
163 return MemberwiseClone();
164 }
165 }
166 然后添加测试代码如下:
167 static void Main() {
168 Cloner mySource = new Cloner(5);
169 Cloner myTarget = (Cloner)mySource.GetCopy();
170 Console.WriteLine("mySource.Val = {0}", mySource.Val);
171 Console.WriteLine("myTarget.Val = {0}", myTarget.Val);
172 mySource.Val = 2;
173 Console.WriteLine("mySource.Val = {0}", mySource.Val);
174 Console.WriteLine("myTarget.Val = {0}", myTarget.Val);
175 Console.ReadKey();
176 }
177 程序的输出结果如下:mySource.Val = 5
178 myTarget.Val = 5
179 mySource.Val = 2
180 myTarget.Val = 5
181 我们发现,这种简单的值类型域的复制,即使改变源对象的值也不会影响复制对象的值,也就是说我们创建了
182 一个新的对象实例,下面我们在来看一个包含引用类型的实例,实例代码和测试代码如下:
183 using System;
184 using System.Collections.Generic;
185 using System.Linq;
186 using System.Windows.Forms;
187
188 namespace Test5 {
189 static class Program {
190 public class Content {
191 public int Val;
192 }
193
194 public class Cloner {
195 public Content MyContent = new Content();
196 public Cloner(int newVal) {
197 MyContent.Val = newVal;
198 }
199
200 public object GetCopy() {
201 return MemberwiseClone();
202 }
203 }
204 /// <summary>
205 /// 应用程序的主入口点。
206 /// </summary>
207 [STAThread]
208 static void Main() {
209 Cloner mySource = new Cloner(5);
210 Cloner myTarget = (Cloner)mySource.GetCopy();
211 Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val);
212 Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val);
213 mySource.MyContent.Val = 2;
214 Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val);
215 Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val);
216 Console.ReadKey();
217 }
218 }
219 }
220 程序的执行结果如下:mySource.Val = 5
221 myTarget.Val = 5
222 mySource.Val = 2
223 myTarget.Val = 2
224 从结果中你可以发现,当改变源对象mySource.MyContent.Val的引用类型域的值后通过阴影复制得到的对象
225 myTarget的引用类型域的值同时发生了 改变。这是因为使用MemberwiseClone()只能实现浅度复制,
226 mySource.MyContent引用了与myTarget.MyContent相同的对象实例。为了实现彻底复制,即复制对象与源对
227 象相互独立、互不影响,需要执行深度复制。修改上面的 GetCopy()方法也可以进行深度复制,但最好使
228 用.NET Framework的标准方式。为此,实现ICloneable接口,该接口有一个方法Clone(),这个方法不带参数,
229 返回一个对象类型,其签名和上 面使用的GetCopy()方法相同。下面给出实际的源代码和测试代码:
230 using System;
231 using System.Collections.Generic;
232 using System.Linq;
233 using System.Windows.Forms;
234
235 namespace Test5 {
236 static class Program {
237 public class Content {
238 public int Val;
239 }
240
241 public class Cloner : ICloneable {
242 public Content MyContent = new Content();
243 public Cloner(int newVal) {
244 MyContent.Val = newVal;
245 }
246
247 #region ICloneable 成员
248
249 public object Clone() {
250 Cloner clonedCloner = new Cloner(MyContent.Val);
251 return clonedCloner;
252 }
253
254 #endregion
255 }
256 /// <summary>
257 /// 应用程序的主入口点。
258 /// </summary>
259 [STAThread]
260 static void Main() {
261 Cloner mySource = new Cloner(5);
262 Cloner myTarget = (Cloner)mySource.Clone();
263 Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val);
264 Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val);
265 mySource.MyContent.Val = 2;
266 Console.WriteLine("mySource.MyContent.Val = {0}", mySource.MyContent.Val);
267 Console.WriteLine("myTarget.MyContent.Val = {0}", myTarget.MyContent.Val);
268 Console.ReadKey();
269 }
270 }
271 }
272 程序的运行结果如下:mySource.Val = 5
273 myTarget.Val = 5
274 mySource.Val = 2
275 myTarget.Val = 5
276 从结果你可以看出,通过深度复制,两个对象已经没有任何关系了,对第一个对象的改变没有影响到第二个
277 对象。这里使用的是包含在源Cloner对象(MyContent)中的Content对象的Val字段去创建一个新的Cloner对象。
278 这个域是一个值类型所以不需要进行深度复制。通过ICloneable.Clone方法实现除MemberwiseClone所提供
279 的克隆之外的克隆。