C#学习笔记④——.NET的OOP技术相关

  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         的克隆之外的克隆。
posted @ 2012-08-28 23:23  hello破军  阅读(346)  评论(0编辑  收藏  举报