九、C# 合式类型

本章要描述如何最终完善类型声明。
 
1、重写Ojbect中的成员
 
重写ToString()
默认情况下,在任何对象上调用 ToString()会返回类的完全限定名称,所以有时候需要重载这个函数,来实现更有意义的功能。
 
重写GetHashCode()
当想要重写Equals()的时候,就应该重写GetHashCode()。
在将类作为散列表集合的键使用时,最好 也将GetHashCode()重写。
散列码的作用是生成与对象的值对应的一个数字,从而高效地平衡一个散列表。
重写GetHashCode()时,请参照以下实现原则。(必须是指为了增强性能而需要采取的措施,安全性是指为了保障安全性而需要采取的措施)
必须:相等的对象必须有相等的散列码(若:a.Equals(b),则a.GetHashCode()=b.GetHashCode() )。
必须:针对一个特定的对象,在这个对象的生存期内,GetHashCode()始终应该返回相同的值,即使对象的数据发生了改变。
        在许多时候,应该缓存方法的返回值,从而确保这一点。
必须:GetHashCode()不应引发任何异常;且必须问题能够成功返回一个值。
性能:散列码应尽可能保持唯一。然而,由于散列码返回的只是一个int值,所以只要一种对象包含的值比一个int能够
       容纳得多,那么散列码就肯定存在重复。
性能:可能的散列码值就当在int范围内平均分布。
性能:GetHashCode()的性能应该优化。
性能:两个对象的细微差异应造成散列码值的极大差异。
安全性:攻其者应该难以伪造一个具有特定散列码的对象。攻击的手法是向散列表中填写大量都散列成同一个值的数据。
        散列表的实现会变成O(n),而不是O(1),造成可能的DOS(拒绝服务)攻击。
 
重写Equals()
 
    1、对象同一性和相等的对象值
对象的同一性,是指两个引用 引用的是同一个实例。
Object包含一个名为ReferenceEquals()的静态方法,它能显式地检查这种对象同一性
只有引用类型才可能引用相等,因此提供了对同一性概念的支持。为值类型调用ReferenceEquals()将问题返回false
,因为根据定义,值类型直接包含着它的数据。
即使向ReferenceEquals()的两个传递两只一个值类型参数也是false,因为ReferenceEquals()对值类型
进行了装箱。由于 每个实参都被装到一个不同的箱中,所以它们永远不可能引用相等。
 
    2、实现Equals(),包含对象同一性和相等的对象值,属于自定义的相等。本质上可以任意设置相等算法。
以下是为了判断相等的对象值而写。
为了判断两个对象是否相等(具有相同的标识数据),可以用一个对象的Equals()方法。
在Object中,这个virtual方法的实现是用ReferenceEquals()来评判相等性。
重写Equals()的步骤如下:
      步骤一:检查是否为null
      步骤二:如果是引用类型,就检查引用是否相等
      步骤三:检查数据类型是否相等
      步骤四:调用一个指定了具体类型的辅助方法,它能将操作数视为要比较的类型,而不是一个对象。
      步骤五:可能要检查散列码是否相等   。如果散列码都不相等,就没必要继续执行一次全面的、逐个
        字段的比较。(相等的两个对象不可能散列码不同)
      步骤六:如果基类重写了Equals(),就检查base.Equals()。
      步骤七:比较每一个标识字段,判断是否相等。
      步骤八:重写GetHashCode()
      步骤九:重写==和!=运算符
 
 
相等性实现的指导原则:
1、Equals()、==运算符和!=运算符应该一起实现。
2、一个类型在Equals()、==和!=实现中应该使用相同的算法。
3、实现Equals()、==和!=时,也应该实现一个类型的GetHashCode()方法。
4、GetHashCode()、Equals()、==和!=永远不能引发异常
5、实现IComparable时,与相等性有关的方法也应该实现。
 
 
二、运算符重载
实现任何运算符的过程都称为运算符重载。
以下运算符不可被重载
x.y、f(x)、new、typeof、default、checked、unchecked、delegate、is、as、=和=>。
 
1、比较运算符
  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5  
  6             Angle a = new Angle(12,0,0);
  7             Angle b = new Angle(24,0,0);
  8             Coordinate c1 = new Coordinate();
  9             Coordinate c2 = new Coordinate();
 10             c1.Latitude = a;
 11             c2.Latitude = a;
 12             c1.Longitude = b;
 13             c2.Longitude = b;
 14             Console.WriteLine(c1 == c2);
 15             Console.WriteLine(c1 != c2);
 16             Console.ReadLine();
 17  
 18         }
 19     }
 20     struct Angle
 21     {
 22  
 23         public Angle(int hours, int minutes, int seconds)
 24         {
 25             _Hours = hours;
 26             _Minutes = minutes;
 27             _Seconds = seconds;
 28         }
 29         public int Hours
 30         {
 31             get
 32             {
 33                 return _Hours;
 34             }
 35         }
 36         private int _Hours;
 37         public int Minutes
 38         {
 39             get
 40             {
 41                 return _Minutes;
 42             }
 43         }
 44         private int _Minutes;
 45         public int Seconds
 46         {
 47             get
 48             {
 49                 return _Seconds;
 50             }
 51         }
 52         private int _Seconds;
 53         public Angle Move(int hours, int minutes, int seconds)
 54         {
 55             return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
 56         }
 57     }
 58  
 59     class Coordinate
 60     {
 61         public Angle Latitude
 62         {
 63             get
 64             {
 65                 return _Latitude;
 66             }
 67             set
 68             {
 69                 _Latitude = value;
 70             }
 71         }
 72         private Angle _Latitude;
 73  
 74         public Angle Longitude
 75         {
 76             get
 77             {
 78                 return _Longitude;
 79             }
 80             set
 81             {
 82                 _Longitude = value;
 83             }
 84         }
 85         private Angle _Longitude;
 86         public static bool operator ==(Coordinate leftHandSide, Coordinate rightHandSide)
 87         {
 88             if (ReferenceEquals(leftHandSide, null))
 89             {
 90                 return ReferenceEquals(rightHandSide, null);
 91             }
 92             return (leftHandSide.Equals(rightHandSide));
 93         }
 94         public static bool operator !=(Coordinate leftHandSide, Coordinate rightHandSide)
 95         {
 96             return !(leftHandSide == rightHandSide);
 97  
 98         }
 99         //重写
100         public override bool Equals(object obj)
101         {
102             if (obj == null)
103             {
104                 return false;
105             }
106             //检查类型是否相同
107             if (this.GetType() != obj.GetType())
108             {
109                 return false;
110             }
111             return Equals((Coordinate)obj);
112         }
113         //重载
114         public bool Equals(Coordinate obj)
115         {
116             if (ReferenceEquals(obj, null))
117             {
118                 return false;
119             }
120             //如果引用相同,肯定为true
121             if (ReferenceEquals(this, obj))
122             {
123                 return true;
124             }
125             //如果散列码值不相同,肯定不同。散列码本身就是根据值生成的整形值
126             if (this.GetHashCode() != obj.GetHashCode())
127             {
128                 return false;
129             }
130             //检查基类是否有自定义的Equals()
131             //System.Diagnostics.Debug.Assert(base.GetType() != typeof(object));
132             //if (!base.Equals(obj))
133             //{
134             //    return false;
135             //}
136             //最后,写上自定义的Equals 计算方法
137             return Longitude.Equals(obj.Longitude) && (Latitude.Equals(obj.Latitude));
138         }
139         //重写
140         public override int GetHashCode()
141         {
142             int hashCode = Longitude.GetHashCode();
143             hashCode ^= Latitude.GetHashCode();//使用自定义的计算方法(本处常用异或 )
144             return hashCode;
145         }
输出:true  false
注:因为GetHashCode()返回的并非一定是“独一无二”的值(它只能表明操作数不同),所以不能仅仅依赖它来判断两个对象
是否相等。在检查是否为Null时,不可以用null执行相等性检查。否则,就会递归调用== 或者 Equals(),造成一个只有栈举出才会终止
的死循环。为了避免这个问题,需要调用ReferenceEquals()来检查是否为null。
2、二元运算符 如 +  -
 
  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5  
  6             Angle a = new Angle(8, 20, 20);
  7             Angle b = new Angle(6, 15, 15);
  8             Coordinate c1 = new Coordinate();
  9             Coordinate c2 = new Coordinate();
 10             c1.Latitude = a;
 11             c2.Latitude = a;
 12             c1.Longitude = b;
 13             c2.Longitude = b;
 14             Console.WriteLine(c1 == c2);
 15             Console.WriteLine(c1 != c2);
 16             Console.WriteLine((c1 + c2).ToString());
 17             Console.ReadLine();
 18  
 19         }
 20     }
 21     struct Angle
 22     {
 23  
 24         public Angle(int hours, int minutes, int seconds)
 25         {
 26             _Hours = hours;
 27             _Minutes = minutes;
 28             _Seconds = seconds;
 29         }
 30         public int Hours
 31         {
 32             get
 33             {
 34                 return _Hours;
 35             }
 36         }
 37         private int _Hours;
 38         public int Minutes
 39         {
 40             get
 41             {
 42                 return _Minutes;
 43             }
 44         }
 45         private int _Minutes;
 46         public int Seconds
 47         {
 48             get
 49             {
 50                 return _Seconds;
 51             }
 52         }
 53         private int _Seconds;
 54         public Angle Move(int hours, int minutes, int seconds)
 55         {
 56             return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
 57         }
 58     }
 59  
 60     class Coordinate
 61     {
 62         public Angle Latitude
 63         {
 64             get
 65             {
 66                 return _Latitude;
 67             }
 68             set
 69             {
 70                 _Latitude = value;
 71             }
 72         }
 73         private Angle _Latitude;
 74  
 75         public Angle Longitude
 76         {
 77             get
 78             {
 79                 return _Longitude;
 80             }
 81             set
 82             {
 83                 _Longitude = value;
 84             }
 85         }
 86         private Angle _Longitude;
 87  
 88         public static bool operator ==(Coordinate leftHandSide, Coordinate rightHandSide)
 89         {
 90             if (ReferenceEquals(leftHandSide, null))
 91             {
 92                 return ReferenceEquals(rightHandSide, null);
 93             }
 94             return (leftHandSide.Equals(rightHandSide));
 95         }
 96         public static bool operator !=(Coordinate leftHandSide, Coordinate rightHandSide)
 97         {
 98             return !(leftHandSide == rightHandSide);
 99  
100         }
101         public static Coordinate operator +(Coordinate leftHandSide, Coordinate rightHandSide)
102         {
103             Coordinate a = new Coordinate();
104             a.Latitude = new Angle(
105                 leftHandSide.Latitude.Hours + rightHandSide.Latitude.Hours,
106                 leftHandSide.Latitude.Minutes + rightHandSide.Latitude.Minutes,
107                 leftHandSide.Latitude.Seconds + rightHandSide.Latitude.Seconds
108                 );
109             a.Longitude = new Angle(
110               leftHandSide.Longitude.Hours + rightHandSide.Longitude.Hours,
111               leftHandSide.Longitude.Minutes + rightHandSide.Longitude.Minutes,
112               leftHandSide.Longitude.Seconds + rightHandSide.Longitude.Seconds
113               );
114             return a;
115         }
116         //重写
117         public override bool Equals(object obj)
118         {
119             if (obj == null)
120             {
121                 return false;
122             }
123             //检查类型是否相同
124             if (this.GetType() != obj.GetType())
125             {
126                 return false;
127             }
128             return Equals((Coordinate)obj);
129         }
130         //重载
131         public bool Equals(Coordinate obj)
132         {
133             if (ReferenceEquals(obj, null))
134             {
135                 return false;
136             }
137             //如果引用相同,肯定为true
138             if (ReferenceEquals(this, obj))
139             {
140                 return true;
141             }
142             //如果散列码值不相同,肯定不同。散列码本身就是根据值生成的整形值
143             if (this.GetHashCode() != obj.GetHashCode())
144             {
145                 return false;
146             }
147             //检查基类是否有自定义的Equals()
148             //System.Diagnostics.Debug.Assert(base.GetType() != typeof(object));
149             //if (!base.Equals(obj))
150             //{
151             //    return false;
152             //}
153             //最后,写上自定义的Equals 计算方法
154             return Longitude.Equals(obj.Longitude) && (Latitude.Equals(obj.Latitude));
155         }
156         //重写
157         public override int GetHashCode()
158         {
159             int hashCode = Longitude.GetHashCode();
160             hashCode ^= Latitude.GetHashCode();//使用自定义的计算方法(本处常用异或 )
161             return hashCode;
162         }
163         //重写
164         public override string ToString()
165         {
166             string str = "";
167             str = "Latitude  " + ((Latitude.Hours.ToString().Length == 2) ? Latitude.Hours.ToString() : "0" + Latitude.Hours.ToString()) + ":"
168                  + ((Latitude.Minutes.ToString().Length == 2) ? Latitude.Minutes.ToString() : "0" + Latitude.Minutes.ToString()) + ":"
169                  + ((Latitude.Hours.ToString().Length == 2) ? Latitude.Seconds.ToString() : "0" + Latitude.Seconds.ToString());
170             str += "
";
171             str += "Longitude  " + ((Longitude.Hours.ToString().Length == 2) ? Longitude.Hours.ToString() : "0" + Longitude.Hours.ToString()) + ":"
172                  + ((Longitude.Minutes.ToString().Length == 2) ? Longitude.Minutes.ToString() : "0" + Longitude.Minutes.ToString()) + ":"
173                  + ((Longitude.Hours.ToString().Length == 2) ? Longitude.Seconds.ToString() : "0" + Longitude.Seconds.ToString());
174             return str;
175         }
176     }
输出:
True
False
Latitude  16:40:40
Longitude  12:30:30
3、赋值运算符与二元运算符的结合
只要重载了二元运算符,就自动重载了赋值运算符与二元运算符的结合(+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=)
定义好一个二元运算符后,C#会自动允许将赋值与运算符结合起来作用。
4、条件逻辑运算符
条件运算符 && ||不可以进行重载,但是可以对 & 和 |进行重载 。为了允许一个类型求值为true或false(比如在一个if语句中),有必要
对true/false一元运算符进行重写。
5、一元运算符
  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5  
  6             Angle a = new Angle(8, 20, 20);
  7             Angle b = new Angle(6, 15, 15);
  8             Coordinate c1 = new Coordinate();
  9             c1.Latitude = -a;
 10             c1.Longitude = -b;
 11  
 12             Console.WriteLine(c1 );
 13  
 14             Console.ReadLine();
 15  
 16         }
 17     }
 18     struct Angle
 19     {
 20  
 21         public Angle(int hours, int minutes, int seconds)
 22         {
 23             _Hours = hours;
 24             _Minutes = minutes;
 25             _Seconds = seconds;
 26         }
 27         public int Hours
 28         {
 29             get
 30             {
 31                 return _Hours;
 32             }
 33         }
 34         private int _Hours;
 35         public int Minutes
 36         {
 37             get
 38             {
 39                 return _Minutes;
 40             }
 41         }
 42         private int _Minutes;
 43         public int Seconds
 44         {
 45             get
 46             {
 47                 return _Seconds;
 48             }
 49         }
 50         private int _Seconds;
 51         public Angle Move(int hours, int minutes, int seconds)
 52         {
 53             return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
 54         }
 55         //一元运算符重载
 56         public static Angle operator -(Angle a)
 57         {
 58             Angle temp = new Angle();
 59             temp._Hours = 24-a.Hours;
 60             temp._Minutes = 60-a.Minutes;
 61             temp._Seconds =60- a.Seconds;
 62             return temp;
 63         }
 64     }
 65  
 66     class Coordinate
 67     {
 68         public Angle Latitude
 69         {
 70             get
 71             {
 72                 return _Latitude;
 73             }
 74             set
 75             {
 76                 _Latitude = value;
 77             }
 78         }
 79         private Angle _Latitude;
 80  
 81         public Angle Longitude
 82         {
 83             get
 84             {
 85                 return _Longitude;
 86             }
 87             set
 88             {
 89                 _Longitude = value;
 90             }
 91         }
 92         private Angle _Longitude;
 93  
 94         //二元运算符重载
 95         public static bool operator ==(Coordinate leftHandSide, Coordinate rightHandSide)
 96         {
 97             if (ReferenceEquals(leftHandSide, null))
 98             {
 99                 return ReferenceEquals(rightHandSide, null);
100             }
101             return (leftHandSide.Equals(rightHandSide));
102         }
103         public static bool operator !=(Coordinate leftHandSide, Coordinate rightHandSide)
104         {
105             return !(leftHandSide == rightHandSide);
106  
107         }
108         public static Coordinate operator +(Coordinate leftHandSide, Coordinate rightHandSide)
109         {
110             Coordinate a = new Coordinate();
111             a.Latitude = new Angle(
112                 leftHandSide.Latitude.Hours + rightHandSide.Latitude.Hours,
113                 leftHandSide.Latitude.Minutes + rightHandSide.Latitude.Minutes,
114                 leftHandSide.Latitude.Seconds + rightHandSide.Latitude.Seconds
115                 );
116             a.Longitude = new Angle(
117               leftHandSide.Longitude.Hours + rightHandSide.Longitude.Hours,
118               leftHandSide.Longitude.Minutes + rightHandSide.Longitude.Minutes,
119               leftHandSide.Longitude.Seconds + rightHandSide.Longitude.Seconds
120               );
121             return a;
122         }
123  
124         //Object成员方法重写
125         //重写
126         public override bool Equals(object obj)
127         {
128             if (obj == null)
129             {
130                 return false;
131             }
132             //检查类型是否相同
133             if (this.GetType() != obj.GetType())
134             {
135                 return false;
136             }
137             return Equals((Coordinate)obj);
138         }    
139        
140         public override int GetHashCode()
141         {
142             int hashCode = Longitude.GetHashCode();
143             hashCode ^= Latitude.GetHashCode();//使用自定义的计算方法(本处常用异或 )
144             return hashCode;
145         }
146        
147         public override string ToString()
148         {
149             string str = "";
150             str = "Latitude  " + ((Latitude.Hours.ToString().Length == 2) ? Latitude.Hours.ToString() : "0" + Latitude.Hours.ToString()) + ":"
151                  + ((Latitude.Minutes.ToString().Length == 2) ? Latitude.Minutes.ToString() : "0" + Latitude.Minutes.ToString()) + ":"
152                  + ((Latitude.Hours.ToString().Length == 2) ? Latitude.Seconds.ToString() : "0" + Latitude.Seconds.ToString());
153             str += "
";
154             str += "Longitude  " + ((Longitude.Hours.ToString().Length == 2) ? Longitude.Hours.ToString() : "0" + Longitude.Hours.ToString()) + ":"
155                  + ((Longitude.Minutes.ToString().Length == 2) ? Longitude.Minutes.ToString() : "0" + Longitude.Minutes.ToString()) + ":"
156                  + ((Longitude.Hours.ToString().Length == 2) ? Longitude.Seconds.ToString() : "0" + Longitude.Seconds.ToString());
157             return str;
158         }
159         //重载
160         public bool Equals(Coordinate obj)
161         {
162             if (ReferenceEquals(obj, null))
163             {
164                 return false;
165             }
166             //如果引用相同,肯定为true
167             if (ReferenceEquals(this, obj))
168             {
169                 return true;
170             }
171             //如果散列码值不相同,肯定不同。散列码本身就是根据值生成的整形值
172             if (this.GetHashCode() != obj.GetHashCode())
173             {
174                 return false;
175             }
176             //检查基类是否有自定义的Equals()
177             //System.Diagnostics.Debug.Assert(base.GetType() != typeof(object));
178             //if (!base.Equals(obj))
179             //{
180             //    return false;
181             //}
182             //最后,写上自定义的Equals 计算方法
183             return Longitude.Equals(obj.Longitude) && (Latitude.Equals(obj.Latitude));
184         }
185     }
输出:
Latitude  16:40:40
Longitude  18:45:45
 
            
 1     if (c1)
 2             {
 3                 Console.WriteLine(c1);
 4             }
 5        public static bool operator false(Coordinate c)
 6         {
 7             if (c.Latitude.Hours < 12)
 8             {
 9  
10                 return false;
11             }
12             else
13             {
14                 return true;
15             }
16         }
17         public static bool operator true(Coordinate c)
18         {
19             if (c.Latitude.Hours < 12)
20             {
21                 return false;
22             }
23             else
24             {
25                 return true;
26             }
27         }
6、转换运算符
  //类型转换运算符
 1         public static implicit operator double(Coordinate c)
 2         {
 3             return (double)c.Latitude.Hours;
 4         }
 5         public static implicit operator Coordinate(double hours)
 6         {
 7             Coordinate c = new Coordinate();
 8             c.Latitude = new Angle((int)hours, 0, 0);
 9             return c;
10         }
implict 隐式 explicit显式
注意:实现一个转换运算符时,无论返回值还是参数,都必须是封闭类型,这是为了提供对封装性的支持。C#不允许在被转换类型的作用域
之外指定转换。
 
三、引用其他程序集
C#和底层CLI平台不是将所有代码都放到一个二进制文件中,而是允许你将代码分散到多个程序集中。
这样一来,就可以在多个可执行文件中重用程序集。
1、类库
开发者可以将程序的不同部分转移到一系列单独编译的单元中,这些单元称为类库,或者简单称为库。
然后,程序可以引用和依靠类库来提供自己的一部分功能。这样一来,两个程序就可以依靠同一个类库,
从而在两个程序中共享那个类库的功能,并减少所需的编码量。
 
为了重用一个不同程序集中的代码,需要在运行C#编译器的时候引用程序集。通常,引用的程序集是一个类库。
 
2、附加的类访问修饰符
在类的作用域之外,唯一可用的访问修饰符只有public和internal
 
internal 也可以用来修饰成员
 
protected interanl
 
3、定义命名空间
 
任何数据类型都是用它的命名空间与名称的组合形式来标识的。
事实上,CLR对“命名空间"是一无所知的。在CLR中,类型的名称都是完全限定的类型名称(它的命名空间与名称的组合形式来标识)。
命名空间的定义可以嵌套。
4、XML注释
 
C#自带的XML注释功能。
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
XML一般用来生成API文档。
 
5、垃圾回收
 
垃圾回收明显是"运行时"的一个核心功能。它的作用是回收不再被引用的对象所战胜的内存。
垃圾回收器只负责 回收内存,不处理其他资源,比如数据库连接、句柄(文件、窗口等)、网络端口以及硬件设备(比如串口)等。
除此之外,垃圾回收器根据是否存在引用来决定要清除什么。这暗示着,垃圾回收器处理的是引用对象,而且只回收堆上的内存。
除此之外,它还意味着假如维持对一个对象的引用,不会阻止垃圾回收器重用对象使用的内存。
 
.NET的垃圾回收
很长一段,需要再学习,待笔记 
 
弱引用,弱引用是为创建起来代价较高(开销很大),而且维护开销特别大的对象而设计的。
例如,假如一个很大的对象列表要从一个数据库中加载,并向用户显示。
在这种情况下,加载这个列表的代码是很高的。一旦用户关闭列表,它就应该可以进行垃圾回收。但是,
假如用户多次请求这个列表,那么每一次都需要执行代价高昂的加载动作。
为了解决这个问题,可以使用弱引用。然后,就可以使用代码检查列表是否水尚未削除,就重新引用同一个列表。
 1      private WeakReference Data;
 2         public FileStream GetData()
 3         {
 4             FileStream data = (FileStream)Data.Target;
 5             if (data != null)
 6             {
 7                 return data;
 8             }
 9             else
10             {
11                 //创建新的文件流
12                 return data;
13             }
14         }
 
6、资源清理
6、1终结器(析构函数)
 1   public class TemporaryFileStream
 2     {
 3         private readonly FileStream _Stream;
 4         public FileStream Stream
 5         {
 6             get { return _Stream; }
 7         }
 8         private FileInfo _File = new FileInfo(Path.GetTempFileName());
 9         public FileInfo File
10         {
11             get { return _File; }
12         }
13  
14         public TemporaryFileStream()
15         {
16             _File = new FileInfo(Path.GetTempFileName());
17             _Stream = new FileStream(File.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
18         }
19         ~TemporaryFileStream()
20         {
21             Close();
22         }
23         public void Close()
24         {
25             if (Stream != null)
26             {
27                 Stream.Close();
28             }
29             if (File != null)
30             {
31                 File.Delete();
32             }
33         }
34  
35     }
 
6、2 IDisposable模式
继承这个接口,并重写指定的方法 void Dispose();
在这个方法中,执行一些释放操作。
 1   class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             TemporaryFileStream fileStream = new TemporaryFileStream();
 6             //Use temporary file stream;
 7  
 8             //..
 9  
10             fileStream.Dispose();
11  
12             //..
13  
14  
15  
16         }
17     }
18  
19     public class TemporaryFileStream : IDisposable
20     {
21         private readonly FileStream _Stream;
22         public FileStream Stream
23         {
24             get { return _Stream; }
25         }
26         private FileInfo _File = new FileInfo(Path.GetTempFileName());
27         public FileInfo File
28         {
29             get { return _File; }
30         }
31  
32         public TemporaryFileStream()
33         {
34             _File = new FileInfo(Path.GetTempFileName());
35             _Stream = new FileStream(File.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
36         }
37         ~TemporaryFileStream()
38         {
39             Close();
40         }
41         public void Close()
42         {
43             if (Stream != null)
44             {
45                 Stream.Close();
46             }
47             if (File != null)
48             {
49                 File.Delete();
50             }
51             // Turn off calling the finalizer
52             System.GC.SuppressFinalize(this);
53         }
54         public  void Dispose()
55         {
56             Close();
57         }
58  
59     }
6、3 使用using语句进行确定性终结
1           static void Search()
2         {
3             using (TemporaryFileStream fileStream1 = new TemporaryFileStream(), fileStream2 = new TemporaryFileStream())
4             {
5                 //出了这个范围,会自动被释放
6             }
7         }
在using语句内,可以实例化多个变量,只需用逗号分隔每个变量就可以。
 
7、垃圾回收与终结
System.GC.SuppressFinalize()。
它的作用是从终结队列(f-reachable)队列中移除指定的引用实例。
f-reachable 队列是准备好进行垃圾回收,同时实现终结的所有对象的一个列表。
假如一个对象有终结器,那么“运行时”只有在对象的终结方法被调用之后,才能对这个对象执行垃圾回收。
然而,垃圾回收本身不会调用终结方法。相反,对这种对象的引用会添加到f-reachable队列中,从而在事实上推迟了垃圾回收。
这是由于 f-reachable队列是一个“引用”列表,一个对象只有在它的终结方法得到调用,而且对象引用从f-reachable队列中删除
之后,才会真正成为“垃圾”。
注:对象复活
    调用一个对象的终结方法时,对该对象的引用都已经消失,而且在垃圾回收之前,剩下的唯一一个步骤就是运行终结代码。
然而,完全有可能不慎重新引用一个待终结的对象。这样一来,被重新引用 的对象就不再是不可访问的。
所以,它不能当作垃圾回收掉。然而,假如对象的终结方法已经运行,那么除非显式标记为要进行终结(使用
GC.ReRegisterFinalize()方法),否则终结方法不一定会再次执行。
 
资源利用和终结的指导原则
定义要对资源进行管理的类时,你应该注意以下几点。
只有在对象使用了稀缺或昂贵资源的前提下,才为对象实现finalize。终结器会推迟垃圾回收。
 
有终结器的对应应该实现IDisposable接口来支持确定性终结。
 
终结方法通常调用与IDisposable调用相同的代码、可能就是调用Dispose()方法。
 
终结器就避免造成任何未处理的异常。
 
像Dispose()和Close()这样的确定性终结方法应该调用System.GC.SuppressFinalize(),使垃圾回收更快地发生,
并避免重复进行资源清理。
 
负责资源清理的代码可以多次调用,所以应该是可以重入的。
 
资源清理方法应该足够简单,而且只应着重于清理由终结实例引用 的资源。它们不应引用其他对象。
 
若基类实现了Dispose(),则派生实现应调用基类的实现 
 
应该确保在调用了Dispose()之后,对象不能继续使用。
 
 
8、延迟初始化
不在声明和构造函数中初始化,在属性中get初始化。
 1     class DataCache
 2     {
 3         private TemporaryFileStream _FileStream = null;
 4         public TemporaryFileStream FileStream
 5         {
 6             get
 7             {
 8                 if (_FileStream == null)
 9                 {
10                     _FileStream = new TemporaryFileStream();
11                 }
12                 return _FileStream;
13             }
14         }
15  
16     }
9、为泛型和lambda表达式使用推迟加载
 1   class DataCache
 2     {
 3   
 4         //为泛型和lambda表达式使用推迟加载(C#4.0 CLR添加了一个新类来帮助进行推迟初始化:System.Lazy<T>
 5         private Lazy<TemporaryFileStream> _FileStream = null;
 6  
 7         public DataCache()
 8         {
 9             _FileStream = new Lazy<TemporaryFileStream>(()=>  new TemporaryFileStream() );
10         }
11         public TemporaryFileStream FileStream
12         {
13             get
14             {
15                 return _FileStream.Value;
16             }
17         }
18  
19     }
 
System.Lazy<T> 获取一个参数(T),这个参数标识了System.Lazy<T> 的Value属性要返回的类型。不是将
一个完全构造好的TemporaryFileStream 赋给_FileStream字段。相反,赋给它的是Lazy<TemporaryFileStream>的一个
实例(一个轻量级的调用),将TemporaryFileStream 本身的初始化推迟到访问Value属性的时候才进行(进而访问FileStream属性)
如果除了类型参数(泛型)还使用了委托,甚至可以提供一个函数来指定在访问Value属性值时如何初始化一个对象。
要注意的是:Lambda表达式本身。即()=>  new TemporaryFileStream() 是直到调用Value时才执行的。
Lambda表达式提供了一种方式为将来发生的事情传递指令,但除非显式请求,否则那些指令是不会执行的。
 
 
 
原文地址:https://www.cnblogs.com/tlxxm/p/4604538.html