*重写object的成员
*重写ToString()
int intNuma = 1;
int intNumb = 2;
public override string ToString()
{
return string.Format("{0} {1}",intNuma,intNumb);
}
*重写GetHashCode() [不熟悉]
如果想要重写Equals(),就应该重写GetHashCode(),如果忘记这样做,会显示一条警告信息。
在将类作为散列表集合的键(key)使用时,最好也将GetHashCode()重写。
散列码(hash code)的作用是生成与对象的值相对应的一个数字,从而高效的平衡一个散列表。
想要获得一个良好的GetHashCode()实现,可以参照一下必须:
必须:相等的对象必然有相等的散列码。(若a.Equals(b),则a.GetHashCode()==b.GetHashCode())
必须:针对一个特定的对象,在这个对象的生存期内,GetHashCode()始终返回相同的值,即使对象的数据发生了改变。【缓存方法的返回值,从而确保这一点】
必须:GetHashCode()不应该发生任何异常,总是成功返回一个值。
性能:散列码应尽量可能保持唯一。
性能:可能的散列码应该在int的范围内平均。
性能:GetHashCode() 的性能应该优化。
……
public class Longitude
{
}
public class Latutide
{
}
public struct Coordinate
{
public Coordinate(Longitude longitude, Latutide latutide)
{
_Longitude = longitude;
_Latutide = latutide;
}
public Longitude Longitude { get { return _Longitude; } }
private readonly Longitude _Longitude;
public Latutide Latutide { get { return _Latutide; } }
private readonly Latutide _Latutide;
public override int GetHashCode()
{
int hashCode =Longitude.GetHashCode();
//as long as the hash codes are not equal
if (Longitude.GetHashCode()!=Latutide.GetHashCode())
{
hashCode^=Latutide.GetHashCode();//or
}
return hashCode;//假如基类不是Object,那么应该在XOR运算总包含base.GetHashCode().
}
*重写Equals()
重写Equals()而不重写GetHashCode()会出现一个警告。
“对象同一性”和“相等的对象值” :相等的值类型,相等的引用类型,同一(相等的引用)
值类型本身不可能引用相等。
相等性实现的指导原则
Equals(),==,!=运算符应该一起实现。
一个类型的Equals(),== ,!=实现中应该使用相同的算法。
实现Equals(),==,!= 时,也应该实现一个类型的GetHashCode()方法
GetHashCode(),Equals(),==,!=永远不能引发异常。
实现IComparable时,与相等性有关的方法也要实现。
public class Longitude
{//……
}
public class Latutide
{//……
}
public struct Coordinate
{
public Coordinate(Longitude longitude, Latutide latutide)
{
_Longitude = longitude;
_Latutide = latutide;
}
public Longitude Longitude { get { return _Longitude; } }
private readonly Longitude _Longitude;
public Latutide Latutide { get { return _Latutide; } }
private readonly Latutide _Latutide;
public override bool Equals(object obj)
{
//1.check for null
if (obj == null)
{
return false;
}
//3.equivalent data types
if (this.GetType() != obj.GetType())
{
return false;
}
return base.Equals((Coordinate)obj);
}
public bool Equals(Coordinate obj)
{
//1:Check for null if a reference type
//if (obj == null)
//{
// return false;
// }
//2:checke for ReferenceEquals if this is a reference type
// if (ReferenceEquals(this, obj))
//{
// return ture;
// }
//
//4:Possibly check for equivalent hash coeds
// if (this.GetHashCode() != obj.GetHashCode())
// {
// return false;
// }
//5.check base.equals if base override equals
// System.Diagnostics.Debug.Assert(
// base.GetType()!=typeof(object));
// if(!base.Equals(obj ))
// {
// return false ;
// }
//6:compare identifying fields for queality using an overload of Equals on Longitude
return ((Longitude.Equals(obj.Longitude))&&(Latutide.Equals(obj)));
}
//7.override GetHashCode()
public override int GetHashCode()
{
int hashCode =Longitude.GetHashCode();
//as long as the hash codes are not equal
if (Longitude.GetHashCode()!=Latutide.GetHashCode())
{
hashCode^=Latutide.GetHashCode();//or
}
return hashCode;//假如基类不是Object,那么应该在XOR运算总包含base.GetHashCode().
}
*运算符重载(operator overloading):x.y f(x) new typeof default checked unchecked delegate is as = =>.其中,=作为赋值运算符,是不能实现重载的。
public static bool operator ==(Coordinate leftHandSide , Coordinate rightHandSide)
{
if (ReferenceEquals(leftHandSide, null))
{
return ReferenceEquals(rightHandSide, null);
}
return ReferenceEquals(leftHandSide,rightHandSide);
}
public static bool operator !=(Coordinate leftHandSide,Coordinate RightHandSide)
{
return !(leftHandSide == RightHandSide);
}
*二元运算符:重载成二元static方法,其中这少有一个参数的类型的是包容类型(当前正在重载该元素的类型)。
public struct Arc
{
public Arc(Longitude arclongitude, Latutide arclatutide)
{
_arcLongitude = arclongitude;
_arcLatutide = arclatutide;
}
public Longitude arcLongitude { get { return _arcLongitude; } }
private readonly Longitude _arcLongitude;
public Latutide arcLatutide { get { return _arcLatutide; } }
private readonly Latutide _arcLatutide;
}
public struct Coordinate
{
//...
public static Coordinate operator +(Coordinate source, Arc arc)
{
Coordinate result = new Coordinate(new Longitude(source.Longitude + arc.arcLongitude),new Latutide(source.Latutide+arc.arcLatutide));
return result;
} }//其中,也需要实现Longitude和Latutide中+的实现。
*一元运算符
类似二元运算符,只获取一个参数,该参数也要是包容类型(正在重载运算符的类型)
*重载true和false
public static bool operator false (IsValid item)
public static bool operator true( IsValid item)
***转型运算符():定义转型运算符在形式上类似于定义其他运算符,只要用"operator"替换待转换结果类型。另外,operator关键字后面要跟表示隐式或显示转换的implicit 或explicit。 一般会引发异常的转换都应该是显示的。
public class Latitude
{//……
public Latitude(double decimalDegress)
{
_DecimalDegress=decimalDegress;
}
public double DecimalDegress
{
get
{
return _DecimalDegress;
}
}
private readonly double _DecimalDegress;
//...
public static implicit operator double(Latitude latitude)
{
return latitude.DecimalDegress;
}
public static implicit operator Latitude(double degress)
{
return new Latitude(degress);
}
}
**更改程序集目标
为了将A.cs,B.cs,C.cs编译成类库
> csc /target:library /out:ABC.dll A.cs B.cs C.cs
**引用程序集
C#允许开发者在命令行上引用程序集。具体的选项是/reference(/r缩写),后跟一个引用列表。
csc.exe /R:ABC.dll program.cs
**类型封装
默认情况下,没有任何访问修饰符的类会被定义成internal ,结果是该类无法从程序集的外部访问。C#为类提供的访问修饰符有public和internal。
public :凡是能访问类型的地方,都能访问成员。如果类是internal 的,则成员只在内部可见。如果包容类是public的,public成员就可以从程序集的外部访问。
internal :成员只能从当前程序集中访问。
private
protected:成员可以从包容类以及派生的任何子类中访问,不管程序集是哪个。
protected internal:成员可以从包容程序集内的任何地方访问,并且可以从包容类型的任何派生类中访问,即使派生类在一个不同的程序集中。
*定义命名空间:namespace,可以嵌套。
*XML注释:单行/// 多行/** */
*生成XML文档文件: >csc /doc:Comments.xml DataStorage.cs
*垃圾回收:只处理引用对象,回收堆上的内存。
**弱引用:弱引用不会禁止对一个对象执行垃圾回收,但是他们会维持一个引用。如果你认为一个对象(挥着对象集合)应该进行弱引用,就需要把它赋给System.WeakReference.(如同操作系统中,为多次被访问的数据而设置的高速缓存区)
private WeakReference Data;
public FileStream GetData()
{
//获取当前System.WeakReference对象应用的对象
FileStream data = (FileStream)Data.Target;
if (data != null)
{
return data;
}
else
{
//load data
//...
//create a weak reference to data for use later;
Data.Target = data;
}
return data;
}
*资源清理:它并不是用来清理文件句柄,数据库连接字符串,端口或者其他有限资源的。
*终结器(finalizer)允许程序员编写代码来清理一个类的资源。
//没有参数,没有返回值,没有访问修饰符。
~className()
{
Close();
}
public void Close()
{
if(Stream!=null)
Stream.Close();
}
if(File!=null)
{
File.Delete();
}
*使用using语句进行确定性终结。
在using语句中,可以实例化多个变量,只要用逗号分割,变量需要是相同的类型,而且都实现了IDisposable().为了强制使用相同的类型,数据类型只能指定一次,而不是在每个变量声明之前都指定一次。
class TemporaryFileSystem : IDisposable
{
public TemporaryFileSystem()
{
_File = new FileInfo(Path.GetTempFileName());
_Stream = new FileStream(File.FullName,FileMode.OpenOrCreate,FileAccess.ReadWrite);
}
~TemporaryFileSystem()
{
Close();
}
public void Close()
{
if (Stream != null)
{
Stream.Close();
}
if(File!=null)
{
File.Delete();
}
System.GC.SuppressFinalize(this);
}
public void Dispose()
{
Close();
}
public FileStream Stream
{ get
{
return _Stream;
}
}
private readonly FileStream _Stream;
public FileInfo File
{
get
{
return _File;
}
}
private readonly FileInfo _File;
}
static void search()
{
TemporaryFileSystem fileStream = new TemporaryFileSystem();
//use temporary file stream;
//...
fileStream.Dispose();
//....
//在实例化TemporaryFileSystem之后,并在调用Dispose()之前,有可能发生一个异常。
//假如在这个期间发生异常,Dispose()会等不到调用。为避免这个问题,c#提供了一个using语句。
using (TemporaryFileSystem fileStream1 = new TemporaryFileSystem(),
fileStream2 = new TemporaryFileSystem())
{
//Use Temporary file stream;
}
}
*垃圾回收和终结
上述代码中,System.GC.SuppressFinalize(this);从终结队列(f-reachable)队列中移除TemporaryFileStream类实例,f-reachable是一个引用列表,一个对象只有用在它的终结方法得到调用,而且对象引用从f-reachable队列中删除之后,才会真正成为垃圾。
**延迟初始化:将一个对象的初始化延迟到需要这个对象时进行,就称为“推迟初始化”。
例如,将一个对象的实例化放到另一个的属性的get()方法中,只有在调用属性的get访问器的时,才会实例化对象。
***.net 4.0开始,添加了一个新类版主进行推迟初始化。System.lazy<T>.[不理解]
class DataCache
{
//...
public string FileStreamName { get; set; }
public DataCache()
{
//不理解,程序中也报错
_FileStream = new Lazy<TemporaryFileStream>(() => new TemporaryFileStream(FileStreamName));
}
public TemporaryFileStream FileStream
{
get
{
return _FileStream.Value;
}
}
private Lazy<TemporaryFileStream> _FileStream;
}