标签:基础 copyto else reg 通过 lock als info memory
当声明一个值类型的变量的时候的时候,变量本身包含了值类型的全部字段,值变量分配到线程堆栈(Thread Stack)上。
public struct ValPoint
{
public int x;
public ValPoint(int x)
{
this.x = x;
}
}
//调用
ValPoint vPoint1 = new ValPoint(10);
值类型结构图
struct 自定义构造函数时,构造函数内必须为每个struct成员初始化;
当声明一个引用类型变量,并使用new操作符创建引用类型实例的时候,该引用变量会被分配到线程栈(Stack)上,变量保存了位于堆(Heap)上的引用类型的实例的内存地址。
public class RefPoint
{
public int x;
public RefPoint(int x)
{
this.x = x;
}
}
//调用
RefPoint rPoint1 = new RefPoint(10);
引用类型结构图:
装箱的步骤
将堆创建的对象的地址返回给引用类型变量
int i = 1;
object boxed = i;
拆箱相反的操作,所以装箱和拆箱是耗时的操作。
System.Object基类型中判等方法有3个,对三个方法分析
//比较引用变量是否指向堆(Heap)上的同一实例对象
public static bool ReferenceEquals(object objA, object objB)
{
return objA == objB;
}
//实例方法,供派生类重写(override),(派生类未重写默认用基类,但只有指向同一实例对象返回true)
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
// 如果一个为null返回false
public static bool Equals(object objA, object objB)
{
return objA == objB || (objA != null && objB != null && objA.Equals(objB));
}
下面通过一些代码来验证方法
RefPoint rPoint1 = new RefPoint(1);
RefPoint rPoint2 = rPoint1;
result = (rPoint1 == rPoint2);//True
Console.WriteLine(result);
result = rPoint1.Equals(rPoint2);//True
Console.WriteLine(result);
RefPoint rPoint3 = new RefPoint(2);
RefPoint rPoint4 = new RefPoint(2);
result = (rPoint3 == rPoint4);//False
Console.WriteLine(result);
result = rPoint3.Equals(rPoint4);//False
Console.WriteLine(result);
值类型隐式继承ValueType,ValueType继承Object并override了Equals方法。override后的Equals方法主要比较步骤
public override bool Equals(object obj)
{
//1.传入的对象是否为null
if (obj == null)
{
return false;
}
//2.类型判等
RuntimeType runtimeType = (RuntimeType)base.GetType();
RuntimeType left = (RuntimeType)obj.GetType();
if (left != runtimeType)
{
return false;
}
//3.为系统基本类型可直接比较
if (ValueType.CanCompareBits(this))
{
return ValueType.FastEqualsCheck(this, obj);
}
//4.利用反射遍历值类型成员(这里有递归)
FieldInfo[] fields = runtimeType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int i = 0; i < fields.Length; i++)
{
object obj2 = ((RtFieldInfo)fields[i]).UnsafeGetValue(this);
object obj3 = ((RtFieldInfo)fields[i]).UnsafeGetValue(obj);
if (obj2 == null)
{
if (obj3 != null)
{
return false;
}
}
else if (!obj2.Equals(obj3))
{
return false;
}
}
return true;
}
来电代码验证
ValPoint vPoint1 = new ValPoint(1);
ValPoint vPoint2 = new ValPoint(1);
result = vPoint2.Equals(vPoint2);
Console.WriteLine(result);//True
装箱
ValPoint vPoint1 = new ValPoint(1);
result = object.ReferenceEquals(vPoint1, vPoint1);
Console.WriteLine(result);//False
小伙伴困惑了,为什么明明是同一个变量放回false。其实ReferenceEquals函数的参数类型为object类型,override Equals方法
ValPoint vPoint1 = new ValPoint(1);
ValPoint vPoint2 = new ValPoint(1);
object obj1 = vPoint1;
object obj2 = vPoint2;
result = (obj1.Equals(obj2));//True
返回True,不知大家是否答对。因为struct隐式继承ValueType,所以obj1.Equals(obj2)实际调用的是ValueType类型override的Equals方法。值类型中含有引用类型成员
public struct ValLine
{
public RefPoint rPoint;
public ValPoint vPoint;
public ValLine(RefPoint rPoint,ValPoint vPoint)
{
this.rPoint = rPoint;
this.vPoint = vPoint;
}
}
//调用
RefPoint rPoint = new RefPoint(1);
ValPoint vPoint1 = new ValPoint(1);
ValPoint vPoint2 = new ValPoint(1);
ValLine vLine1 = new ValLine(rPoint, vPoint1);
ValLine vLine2 = new ValLine(rPoint, vPoint2);
result = vLine1.Equals(vLine2);//True
大家怎么想的放回true,ValueType写Equals。利用反射遍历ValLine 类型成员,RefPoint引用类型因为指向堆(Heap)上同一实例未返回false,继续遍历ValPoint 类型下的Equals的方法未返回false。
指的是对 对象的成员来区分的。对象的成员是值类型时会复制其本身;对象的成员是引用类型时仅仅复制引用,而不在堆(Heap)上创建新实例。
引用类型需要怎样实现浅复制,需要实现ICloneable接口。需要添加类
public class RefLine:ICloneable
{
public RefPoint rPoint;
public ValPoint vPoint;
public RefLine(RefPoint rPoint, ValPoint vPoint)
{
this.rPoint = rPoint;
this.vPoint = vPoint;
}
public object Clone()
{
return MemberwiseClone();
}
}
//调用验证值类型
ValPoint vPoint = new ValPoint(1);
RefPoint rPoint = new RefPoint(2);
ValLine vLine1 = new ValLine(rPoint, vPoint);
ValLine vLine2 = vLine1;
vLine2.vPoint.x = 3;
vLine2.rPoint.x = 4;
Console.WriteLine(vLine1.vPoint.x);//1
Console.WriteLine(vLine1.rPoint.x);//4
//调用验证引用类型
ValPoint vPoint = new ValPoint(1);
RefPoint rPoint = new RefPoint(2);
RefLine rLine1 = new RefLine(rPoint, vPoint);
RefLine rLine2 = rLine1.Clone() as RefLine;
rLine2.vPoint.x = 3;
rLine2.rPoint.x = 4;
Console.WriteLine(rLine1.vPoint.x);//1
Console.WriteLine(rLine1.rPoint.x);//4
值类型浅复制结构图:
引用类型浅复制结构图:
深复制就是将引用成员指向的对象也进行复制。引用成员可能指向引用,所以深复制非常复杂,简单的解决办法序列化。
[Serializable]
public struct ValPoint
{
public int x;
public ValPoint(int x)
{
this.x = x;
}
}
[Serializable]
public class RefPoint
{
public int x;
public RefPoint(int x)
{
this.x = x;
}
}
[Serializable]
public class RefLine
{
public RefPoint rPoint;
public ValPoint vPoint;
public RefLine(RefPoint rPoint, ValPoint vPoint)
{
this.rPoint = rPoint;
this.vPoint = vPoint;
}
public object Clone()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this);
//注意设置流的起始位置
ms.Position = 0;
return (bf.Deserialize(ms));
}
}
//调用
ValPoint vPoint = new ValPoint(1);
RefPoint rPoint = new RefPoint(2);
RefLine rLine1 = new RefLine(rPoint, vPoint);
RefLine rLine2 = rLine1.Clone() as RefLine;
rLine2.vPoint.x = 3;
rLine2.rPoint.x = 4;
Console.WriteLine(rLine1.vPoint.x);//1
Console.WriteLine(rLine1.rPoint.x);//2
string类型是一种特殊的引用类型,称作不可变类型。那么我们需要怎样自己创建一个不可变类型?
不可变类型需要具有的两个特性
对象的常量性: 对象的状态一旦确定,就不能再次更改了。
public struct Address
{
//对象的常量型
private readonly string province;
private readonly string city;
private readonly string zip;
//对一般引用类型(常量性需要修改)
private readonly string[] phones;
//保证对象的原子性,构造函数每次要么成功要么失败
public Address(string province, string city, string zip, string[] phones)
{
this.city = city;
this.province = province;
this.zip = zip;
this.phones = phones;
CheckZip(zip);
}
public string Province { get { return province; } }
public string City { get { return city; } }
public string Zip { get { return zip; } }
//防止修改引用类型内的成员变量
private string[] Phones
{
get
{
string[] rtn = new string[phones.Length];
phones.CopyTo(rtn, 0);
return rtn;
}
}
private void CheckZip(string value)
{
string pattern = @"\d{6}";
if (!Regex.IsMatch(value, pattern))
{
throw new Exception("Zip is invalid!");
}
}
}
《.Net 之美》 作者:张子阳
标签:基础 copyto else reg 通过 lock als info memory
原文地址:http://www.cnblogs.com/LoveTomato/p/8006690.html