zoukankan      html  css  js  c++  java
  • 九、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表达式提供了一种方式为将来发生的事情传递指令,但除非显式请求,否则那些指令是不会执行的。
     
     
     
  • 相关阅读:
    使用FRP让内网站点被外网访问
    游戏AI(三)—行为树优化之基于事件的行为树
    游戏AI(二)—行为树优化之内存优化
    游戏AI-行为树理论及实现
    利用InfluxDB和Grafana搭建一个数据监测的仪表盘
    Go语言中slice使用注意事项
    4:ELK分析tomcat日志
    2:tomcat配置优化
    文件操作2-Day3
    MySQL读写分离项目配置
  • 原文地址:https://www.cnblogs.com/tlxxm/p/4604538.html
Copyright © 2011-2022 走看看