本章要描述如何最终完善类型声明。
 
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、比较运算符

     class Program
{
static void Main(string[] args)
{ Angle a = new Angle(,,);
Angle b = new Angle(,,);
Coordinate c1 = new Coordinate();
Coordinate c2 = new Coordinate();
c1.Latitude = a;
c2.Latitude = a;
c1.Longitude = b;
c2.Longitude = b;
Console.WriteLine(c1 == c2);
Console.WriteLine(c1 != c2);
Console.ReadLine(); }
}
struct Angle
{ public Angle(int hours, int minutes, int seconds)
{
_Hours = hours;
_Minutes = minutes;
_Seconds = seconds;
}
public int Hours
{
get
{
return _Hours;
}
}
private int _Hours;
public int Minutes
{
get
{
return _Minutes;
}
}
private int _Minutes;
public int Seconds
{
get
{
return _Seconds;
}
}
private int _Seconds;
public Angle Move(int hours, int minutes, int seconds)
{
return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
}
} class Coordinate
{
public Angle Latitude
{
get
{
return _Latitude;
}
set
{
_Latitude = value;
}
}
private Angle _Latitude; public Angle Longitude
{
get
{
return _Longitude;
}
set
{
_Longitude = value;
}
}
private Angle _Longitude;
public static bool operator ==(Coordinate leftHandSide, Coordinate rightHandSide)
{
if (ReferenceEquals(leftHandSide, null))
{
return ReferenceEquals(rightHandSide, null);
}
return (leftHandSide.Equals(rightHandSide));
}
public static bool operator !=(Coordinate leftHandSide, Coordinate rightHandSide)
{
return !(leftHandSide == rightHandSide); }
//重写
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
//检查类型是否相同
if (this.GetType() != obj.GetType())
{
return false;
}
return Equals((Coordinate)obj);
}
//重载
public bool Equals(Coordinate obj)
{
if (ReferenceEquals(obj, null))
{
return false;
}
//如果引用相同,肯定为true
if (ReferenceEquals(this, obj))
{
return true;
}
//如果散列码值不相同,肯定不同。散列码本身就是根据值生成的整形值
if (this.GetHashCode() != obj.GetHashCode())
{
return false;
}
//检查基类是否有自定义的Equals()
//System.Diagnostics.Debug.Assert(base.GetType() != typeof(object));
//if (!base.Equals(obj))
//{
// return false;
//}
//最后,写上自定义的Equals 计算方法
return Longitude.Equals(obj.Longitude) && (Latitude.Equals(obj.Latitude));
}
//重写
public override int GetHashCode()
{
int hashCode = Longitude.GetHashCode();
hashCode ^= Latitude.GetHashCode();//使用自定义的计算方法(本处常用异或 )
return hashCode;
}
输出:true  false
注:因为GetHashCode()返回的并非一定是“独一无二”的值(它只能表明操作数不同),所以不能仅仅依赖它来判断两个对象
是否相等。在检查是否为Null时,不可以用null执行相等性检查。否则,就会递归调用== 或者 Equals(),造成一个只有栈举出才会终止
的死循环。为了避免这个问题,需要调用ReferenceEquals()来检查是否为null。
2、二元运算符 如 +  -

     class Program
{
static void Main(string[] args)
{ Angle a = new Angle(, , );
Angle b = new Angle(, , );
Coordinate c1 = new Coordinate();
Coordinate c2 = new Coordinate();
c1.Latitude = a;
c2.Latitude = a;
c1.Longitude = b;
c2.Longitude = b;
Console.WriteLine(c1 == c2);
Console.WriteLine(c1 != c2);
Console.WriteLine((c1 + c2).ToString());
Console.ReadLine(); }
}
struct Angle
{ public Angle(int hours, int minutes, int seconds)
{
_Hours = hours;
_Minutes = minutes;
_Seconds = seconds;
}
public int Hours
{
get
{
return _Hours;
}
}
private int _Hours;
public int Minutes
{
get
{
return _Minutes;
}
}
private int _Minutes;
public int Seconds
{
get
{
return _Seconds;
}
}
private int _Seconds;
public Angle Move(int hours, int minutes, int seconds)
{
return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
}
} class Coordinate
{
public Angle Latitude
{
get
{
return _Latitude;
}
set
{
_Latitude = value;
}
}
private Angle _Latitude; public Angle Longitude
{
get
{
return _Longitude;
}
set
{
_Longitude = value;
}
}
private Angle _Longitude; public static bool operator ==(Coordinate leftHandSide, Coordinate rightHandSide)
{
if (ReferenceEquals(leftHandSide, null))
{
return ReferenceEquals(rightHandSide, null);
}
return (leftHandSide.Equals(rightHandSide));
}
public static bool operator !=(Coordinate leftHandSide, Coordinate rightHandSide)
{
return !(leftHandSide == rightHandSide); }
public static Coordinate operator +(Coordinate leftHandSide, Coordinate rightHandSide)
{
Coordinate a = new Coordinate();
a.Latitude = new Angle(
leftHandSide.Latitude.Hours + rightHandSide.Latitude.Hours,
leftHandSide.Latitude.Minutes + rightHandSide.Latitude.Minutes,
leftHandSide.Latitude.Seconds + rightHandSide.Latitude.Seconds
);
a.Longitude = new Angle(
leftHandSide.Longitude.Hours + rightHandSide.Longitude.Hours,
leftHandSide.Longitude.Minutes + rightHandSide.Longitude.Minutes,
leftHandSide.Longitude.Seconds + rightHandSide.Longitude.Seconds
);
return a;
}
//重写
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
//检查类型是否相同
if (this.GetType() != obj.GetType())
{
return false;
}
return Equals((Coordinate)obj);
}
//重载
public bool Equals(Coordinate obj)
{
if (ReferenceEquals(obj, null))
{
return false;
}
//如果引用相同,肯定为true
if (ReferenceEquals(this, obj))
{
return true;
}
//如果散列码值不相同,肯定不同。散列码本身就是根据值生成的整形值
if (this.GetHashCode() != obj.GetHashCode())
{
return false;
}
//检查基类是否有自定义的Equals()
//System.Diagnostics.Debug.Assert(base.GetType() != typeof(object));
//if (!base.Equals(obj))
//{
// return false;
//}
//最后,写上自定义的Equals 计算方法
return Longitude.Equals(obj.Longitude) && (Latitude.Equals(obj.Latitude));
}
//重写
public override int GetHashCode()
{
int hashCode = Longitude.GetHashCode();
hashCode ^= Latitude.GetHashCode();//使用自定义的计算方法(本处常用异或 )
return hashCode;
}
//重写
public override string ToString()
{
string str = "";
str = "Latitude " + ((Latitude.Hours.ToString().Length == ) ? Latitude.Hours.ToString() : "" + Latitude.Hours.ToString()) + ":"
+ ((Latitude.Minutes.ToString().Length == ) ? Latitude.Minutes.ToString() : "" + Latitude.Minutes.ToString()) + ":"
+ ((Latitude.Hours.ToString().Length == ) ? Latitude.Seconds.ToString() : "" + Latitude.Seconds.ToString());
str += "\n";
str += "Longitude " + ((Longitude.Hours.ToString().Length == ) ? Longitude.Hours.ToString() : "" + Longitude.Hours.ToString()) + ":"
+ ((Longitude.Minutes.ToString().Length == ) ? Longitude.Minutes.ToString() : "" + Longitude.Minutes.ToString()) + ":"
+ ((Longitude.Hours.ToString().Length == ) ? Longitude.Seconds.ToString() : "" + Longitude.Seconds.ToString());
return str;
}
}
输出:
True
False
Latitude  16:40:40
Longitude  12:30:30
3、赋值运算符与二元运算符的结合
只要重载了二元运算符,就自动重载了赋值运算符与二元运算符的结合(+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=)
定义好一个二元运算符后,C#会自动允许将赋值与运算符结合起来作用。
4、条件逻辑运算符
条件运算符 && ||不可以进行重载,但是可以对 & 和 |进行重载 。为了允许一个类型求值为true或false(比如在一个if语句中),有必要
对true/false一元运算符进行重写。
5、一元运算符

     class Program
{
static void Main(string[] args)
{ Angle a = new Angle(, , );
Angle b = new Angle(, , );
Coordinate c1 = new Coordinate();
c1.Latitude = -a;
c1.Longitude = -b; Console.WriteLine(c1 ); Console.ReadLine(); }
}
struct Angle
{ public Angle(int hours, int minutes, int seconds)
{
_Hours = hours;
_Minutes = minutes;
_Seconds = seconds;
}
public int Hours
{
get
{
return _Hours;
}
}
private int _Hours;
public int Minutes
{
get
{
return _Minutes;
}
}
private int _Minutes;
public int Seconds
{
get
{
return _Seconds;
}
}
private int _Seconds;
public Angle Move(int hours, int minutes, int seconds)
{
return new Angle(Hours + hours, Minutes + minutes, Seconds + seconds);
}
//一元运算符重载
public static Angle operator -(Angle a)
{
Angle temp = new Angle();
temp._Hours = -a.Hours;
temp._Minutes = -a.Minutes;
temp._Seconds =- a.Seconds;
return temp;
}
} class Coordinate
{
public Angle Latitude
{
get
{
return _Latitude;
}
set
{
_Latitude = value;
}
}
private Angle _Latitude; public Angle Longitude
{
get
{
return _Longitude;
}
set
{
_Longitude = value;
}
}
private Angle _Longitude; //二元运算符重载
public static bool operator ==(Coordinate leftHandSide, Coordinate rightHandSide)
{
if (ReferenceEquals(leftHandSide, null))
{
return ReferenceEquals(rightHandSide, null);
}
return (leftHandSide.Equals(rightHandSide));
}
public static bool operator !=(Coordinate leftHandSide, Coordinate rightHandSide)
{
return !(leftHandSide == rightHandSide); }
public static Coordinate operator +(Coordinate leftHandSide, Coordinate rightHandSide)
{
Coordinate a = new Coordinate();
a.Latitude = new Angle(
leftHandSide.Latitude.Hours + rightHandSide.Latitude.Hours,
leftHandSide.Latitude.Minutes + rightHandSide.Latitude.Minutes,
leftHandSide.Latitude.Seconds + rightHandSide.Latitude.Seconds
);
a.Longitude = new Angle(
leftHandSide.Longitude.Hours + rightHandSide.Longitude.Hours,
leftHandSide.Longitude.Minutes + rightHandSide.Longitude.Minutes,
leftHandSide.Longitude.Seconds + rightHandSide.Longitude.Seconds
);
return a;
} //Object成员方法重写
//重写
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
//检查类型是否相同
if (this.GetType() != obj.GetType())
{
return false;
}
return Equals((Coordinate)obj);
} public override int GetHashCode()
{
int hashCode = Longitude.GetHashCode();
hashCode ^= Latitude.GetHashCode();//使用自定义的计算方法(本处常用异或 )
return hashCode;
} public override string ToString()
{
string str = "";
str = "Latitude " + ((Latitude.Hours.ToString().Length == ) ? Latitude.Hours.ToString() : "" + Latitude.Hours.ToString()) + ":"
+ ((Latitude.Minutes.ToString().Length == ) ? Latitude.Minutes.ToString() : "" + Latitude.Minutes.ToString()) + ":"
+ ((Latitude.Hours.ToString().Length == ) ? Latitude.Seconds.ToString() : "" + Latitude.Seconds.ToString());
str += "\n";
str += "Longitude " + ((Longitude.Hours.ToString().Length == ) ? Longitude.Hours.ToString() : "" + Longitude.Hours.ToString()) + ":"
+ ((Longitude.Minutes.ToString().Length == ) ? Longitude.Minutes.ToString() : "" + Longitude.Minutes.ToString()) + ":"
+ ((Longitude.Hours.ToString().Length == ) ? Longitude.Seconds.ToString() : "" + Longitude.Seconds.ToString());
return str;
}
//重载
public bool Equals(Coordinate obj)
{
if (ReferenceEquals(obj, null))
{
return false;
}
//如果引用相同,肯定为true
if (ReferenceEquals(this, obj))
{
return true;
}
//如果散列码值不相同,肯定不同。散列码本身就是根据值生成的整形值
if (this.GetHashCode() != obj.GetHashCode())
{
return false;
}
//检查基类是否有自定义的Equals()
//System.Diagnostics.Debug.Assert(base.GetType() != typeof(object));
//if (!base.Equals(obj))
//{
// return false;
//}
//最后,写上自定义的Equals 计算方法
return Longitude.Equals(obj.Longitude) && (Latitude.Equals(obj.Latitude));
}
}
输出:
Latitude  16:40:40
Longitude  18:45:45
 

     if (c1)
{
Console.WriteLine(c1);
}
    public static bool operator false(Coordinate c)
{
if (c.Latitude.Hours < )
{ return false;
}
else
{
return true;
}
}
public static bool operator true(Coordinate c)
{
if (c.Latitude.Hours < )
{
return false;
}
else
{
return true;
}
}
6、转换运算符
  //类型转换运算符
         public static implicit operator double(Coordinate c)
{
return (double)c.Latitude.Hours;
}
public static implicit operator Coordinate(double hours)
{
Coordinate c = new Coordinate();
c.Latitude = new Angle((int)hours, , );
return c;
}

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的垃圾回收
很长一段,需要再学习,待笔记 
 
弱引用,弱引用是为创建起来代价较高(开销很大),而且维护开销特别大的对象而设计的。
例如,假如一个很大的对象列表要从一个数据库中加载,并向用户显示。
在这种情况下,加载这个列表的代码是很高的。一旦用户关闭列表,它就应该可以进行垃圾回收。但是,
假如用户多次请求这个列表,那么每一次都需要执行代价高昂的加载动作。
为了解决这个问题,可以使用弱引用。然后,就可以使用代码检查列表是否水尚未削除,就重新引用同一个列表。

      private WeakReference Data;
public FileStream GetData()
{
FileStream data = (FileStream)Data.Target;
if (data != null)
{
return data;
}
else
{
//创建新的文件流
return data;
}
}
 
6、资源清理
6、1终结器(析构函数)

   public class TemporaryFileStream
{
private readonly FileStream _Stream;
public FileStream Stream
{
get { return _Stream; }
}
private FileInfo _File = new FileInfo(Path.GetTempFileName());
public FileInfo File
{
get { return _File; }
} public TemporaryFileStream()
{
_File = new FileInfo(Path.GetTempFileName());
_Stream = new FileStream(File.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
}
~TemporaryFileStream()
{
Close();
}
public void Close()
{
if (Stream != null)
{
Stream.Close();
}
if (File != null)
{
File.Delete();
}
} }
 
6、2 IDisposable模式
继承这个接口,并重写指定的方法 void Dispose();
在这个方法中,执行一些释放操作。

   class Program
{
static void Main(string[] args)
{
TemporaryFileStream fileStream = new TemporaryFileStream();
//Use temporary file stream; //.. fileStream.Dispose(); //.. }
} public class TemporaryFileStream : IDisposable
{
private readonly FileStream _Stream;
public FileStream Stream
{
get { return _Stream; }
}
private FileInfo _File = new FileInfo(Path.GetTempFileName());
public FileInfo File
{
get { return _File; }
} public TemporaryFileStream()
{
_File = new FileInfo(Path.GetTempFileName());
_Stream = new FileStream(File.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
}
~TemporaryFileStream()
{
Close();
}
public void Close()
{
if (Stream != null)
{
Stream.Close();
}
if (File != null)
{
File.Delete();
}
// Turn off calling the finalizer
System.GC.SuppressFinalize(this);
}
public void Dispose()
{
Close();
} }
6、3 使用using语句进行确定性终结

           static void Search()
{
using (TemporaryFileStream fileStream1 = new TemporaryFileStream(), fileStream2 = new TemporaryFileStream())
{
//出了这个范围,会自动被释放
}
}
在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初始化。

     class DataCache
{
private TemporaryFileStream _FileStream = null;
public TemporaryFileStream FileStream
{
get
{
if (_FileStream == null)
{
_FileStream = new TemporaryFileStream();
}
return _FileStream;
}
} }
9、为泛型和lambda表达式使用推迟加载

   class DataCache
{ //为泛型和lambda表达式使用推迟加载(C#4.0 CLR添加了一个新类来帮助进行推迟初始化:System.Lazy<T>
private Lazy<TemporaryFileStream> _FileStream = null; public DataCache()
{
_FileStream = new Lazy<TemporaryFileStream>(()=> new TemporaryFileStream() );
}
public TemporaryFileStream FileStream
{
get
{
return _FileStream.Value;
}
} }
 
System.Lazy<T> 获取一个参数(T),这个参数标识了System.Lazy<T> 的Value属性要返回的类型。不是将
一个完全构造好的TemporaryFileStream 赋给_FileStream字段。相反,赋给它的是Lazy<TemporaryFileStream>的一个
实例(一个轻量级的调用),将TemporaryFileStream 本身的初始化推迟到访问Value属性的时候才进行(进而访问FileStream属性)
如果除了类型参数(泛型)还使用了委托,甚至可以提供一个函数来指定在访问Value属性值时如何初始化一个对象。
要注意的是:Lambda表达式本身。即()=>  new TemporaryFileStream() 是直到调用Value时才执行的。
Lambda表达式提供了一种方式为将来发生的事情传递指令,但除非显式请求,否则那些指令是不会执行的。
 
 
 

九、C# 合式类型的更多相关文章

  1. JSP JSP工作原理 JSP语法 JSP声明 JSP注释 JSP指令 jsp九大隐式/内置对象

    1 什么是JSP   1)为什么说,Servlet是一个动态Web开发技术呢?     Servlet是基于服务端的一种动态交互技术,     HttpServletRequest表示客户端到服务端的 ...

  2. JSP页面以及JSP九大隐式对象

    €JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. €JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比 ...

  3. jsp学习--JSP运行原理,九大隐式对象和JSP常用标签

    一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...

  4. JSP--JSP语法--指令---九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构

    一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1. JSP模板元素:JSP中HTML标 ...

  5. JSP--JSP语法--指令--include(动态包含/静态包含)--九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构

    一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1.    JSP模板元素:JSP中HT ...

  6. JSP九大隐式对象和四大域对象-----面试

    因为jsp实质是一个Servlet对象:jsp在第一次访问时会被Web容器翻译成Servlet,在执行过程:第一次访问---->inex.jsp---->index_jsp.java--- ...

  7. C#中的隐式类型var——详细示例解析

    从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,它的具体类型由编译器根据上下文推断而出. 下面就让我来总结下隐式类型的一些特点: 1.va ...

  8. C++中的显式类型转化

    类型转化也许大家并不陌生,int i; float j; j = (float)i; i = (int)j; 像这样的显式转化其实很常见,强制类型转换可能会丢失部分数据,所以如果不加(int)做强制转 ...

  9. .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

    开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量.但是,在开心欢乐之余,我们也 ...

随机推荐

  1. 【canvas】基于坐标的碰撞检测 / 基本的动画 / 多物体动画

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. Move Zeroes——Leetcode

    Given an array nums, write a function to move all 0's to the end of it while maintaining the relativ ...

  3. Qt 与 JavaScript 通信

    使用QWebView加载网页后,解决Qt与JavaScript通信的问题: The QtWebKit Bridge :http://qt-project.org/doc/qt-4.8/qtwebkit ...

  4. std::numeric_limits<int>::max() error C2589: '(' : illegal token on right side of '::' 解决办法

    int max =std::numeric_limits<int>::max();     根据错误提示: f:\code\cpp\webspider\main.cpp(47) : war ...

  5. c语言运算符号详细说明

    C语言中具有右结合性的运算符包括所有单目运算符以及赋值运算符(=)和条件运算符.其它都是左结合性. 判断表达式计算顺序时,先按优先级高的先计算,优先级低的后计算,当优先级相同时再按结合性,或从左至右顺 ...

  6. 折腾iPhone的生活——运营商信号显示数据化

    iOS7以后iphone的信号都是用5个小圆圈显示的,像这样 但是还有种显示方法可以用数字信号显示信号量,比较适合很专注于生活品质的人和对数字有偏爱的人,像这样: 这样还有个好处是可以节约顶部状态栏的 ...

  7. Bzoj 1696: [Usaco2007 Feb]Building A New Barn新牛舍 中位数,数学

    1696: [Usaco2007 Feb]Building A New Barn新牛舍 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 394  Solve ...

  8. (转)WS2008远程桌面连接时提示:“要登录到此远程计算机,您必须被授予允许通过终端服务登录的权限”的解决办法

    原文:http://www.chunfengxiyu.com/ws2008-mstsc-privilege.html WS2008远程桌面连接时提示:“要登录到此远程计算机,您必须被授予允许通过终端服 ...

  9. [JIT_APP]Java基础知识总结

    一.Java语言的基础知识 1. 开发Java语言的公司 美国Sun(Sum Microsystems)公司开发.   2.Java的3个版本 J2SE(Java2 Standard Edition) ...

  10. mysql 主从同步配置

    1  环境 mac air 主机做 主库,使用的是XAMPP自带的mysql 版本为 5.6.21, for osx10.6 (x86_64) 虚拟机mysql 做从库  版本为 5.5.38, fo ...