值类型与引用类型(下)
[下载]:[类型示例代码]
1. 引言
值类型与引用类型的话题经过了两个回合([第八回:品味类型---值类型与引用类型(上)-内存有理]和[第九回:品味类型---值类型与引用类型(中)-规则无边])的讨论和切磋,我们就基本的理解层面来说已经差不多了,但是对这一部分的进一步把握和更深刻的理解还要继续和深化,因为我自己就在两篇发布之际,我就得到装配脑袋兄的不倦指导,之后又查阅了很多的资料发现类型在.NET或者说语言基础中何其重要的内涵和深度,因此关于这个话题的讨论还没有停止,以后我将继续分享自己的所得与所感。
不过作为一个阶段,本文将值类型和引用类型的讨论从应用示例角度来进一步做以延伸,可以看作是对前两回的补充性探讨。我们从类型定义、实例创建、参数传递、类型判等、垃圾回收等几个方面来简要的对上两回的内容做以剖析,并以一定的IL语言和内存机制来说明,期望进一步加深我们的理解和分析。
2. 以代码剖析
下面,我们以一个经典的值类型和引用类型对比的示例来剖析,其区别和实质。在剖析的过程中,我们主要以执行分析(主要是代码注释)、内存分析(主要是图例说明)和IL分析(主要是IL代码简析)三个方面来逐知识点解析,最后再做以总结描述,这样就可以有更深的理解。
2.1 类型定义
定义简单的值类型MyStruct和引用类型MyClass,在后面的示例中将逐渐完善,完整的代码可以点击下载[类型示例代码]。我们的讨论现在开始,
// 01 定义值类型public struct MyStruct
{
private int _myNo;
public int MyNo
{
get { return _myNo; }
set { _myNo = value; }
}
public MyStruct(int myNo)
{
_myNo = myNo;
}
public void ShowNo()
{
Console.WriteLine(_myNo);
}
}
// 02 定义引用类型
public class MyClass
{
private int _myNo;
public int MyNo
{
get { return _myNo; }
set { _myNo = value; }
}
public MyClass()
{
_myNo = 0;
}
public MyClass(int myNo)
{
_myNo = myNo;
}
public void ShowNo()
{
Console.WriteLine(_myNo);
}
} IL分析
分析IL代码可知,静态方法.ctor用来表示实现构造方法的定义,其中该段IL代码表示将0赋给字段_myNo。
2.2 创建实例、初始化及赋值
接下来,我们完成实例创建和初始化,和简单的赋值操作,然后在内存和IL分析中发现其实质。
创建实例、初始化及赋值首先是值类型和引用类型的定义,这是一切面向对象的开始,
然后是初始化过程,
简单的赋值和拷贝,是最基本的内存操作,不妨看看,
2.3 参数传递
参数传递
不必多说,就是一个简要阐释,对于参数的传递作者将计划以更多的笔墨来在后面的系列中做以澄清和深入。
2.4 类型转换
类型转换的演示,包括很多个方面,在此我们只以自定义类型转换为例来做以说明,更详细的类型转换可以参考[第九回:品味类型---值类型与引用类型(中)-规则无边]的[再论类型转换部分]。
首先是值类型的自定义类型转换,
public struct MyStruct
{
// 01.2 自定义类型转:整形- MyStruct型
static public explicit operator MyStruct(int myNo)
{
return new MyStruct(myNo);
}
}
然后是引用类型的自定义类型转换,
public class MyClass
{
// 02.2 自定义类型转换:MyClass- string型
static public implicit operator string(MyClass mc)
{
return mc.ToString();
}
public override string ToString()
{
return _myNo.ToString();
}
}
最后,我们对自定义的类型做以测试,
{
#region 03. 类型转换
MyStruct MyNum;
int i = 100;
MyNum = (MyStruct)i;
Console.WriteLine("整形显式转换为MyStruct型---");
Console.WriteLine(i);
MyClass MyCls = new MyClass(200);
string str = MyCls;
Console.WriteLine("MyClass型隐式转换为string型---");
Console.WriteLine(str);
#endregion
}
2.5 类型判等
类型判等主要包括:ReferenceEquals()、Equals()虚方法和静态方法、==操作符等方面,同时注意在值类型和引用类型判等时的不同之处,可以参考[第九回:品味类型---值类型与引用类型(中)-规则无边]的[4. 再论类型判等]的简述。
代码演示
// 01 定义值类型
public struct MyStruct
{
// 01.1 值类型的类型判等
public override bool Equals(object obj)
{
return base.Equals(obj);
}
}
public class MyClass
{
// 02.1 引用类型的类型判等
public override bool Equals(object obj)
{
return base.Equals(obj);
}
}
public static void Main(string[] args)
{
#region 05 类型判等
Console.WriteLine("类型判等---");
// 05.1 ReferenceEquals判等
//值类型总是返回false,经过两次装箱的myStruct不可能指向同一地址
Console.WriteLine(ReferenceEquals(myStruct, myStruct));
//同一引用类型对象,将指向同样的内存地址
Console.WriteLine(ReferenceEquals(myClass, myClass));
//RefenceEquals认为null等于null,因此返回true
Console.WriteLine(ReferenceEquals(null, null));
// 05.2 Equals判等
//重载的值类型判等方法,成员大小不同
Console.WriteLine(myStruct.Equals(myStruct2)) ;
//重载的引用类型判等方法,指向引用相同
Console.WriteLine(myClass.Equals(myClass2));
#endregion
}
2.6 垃圾回收
首先,垃圾回收机制,绝对不是三言两语就能交代清楚,分析明白的。因此,本示例只是从最简单的说明出发,对垃圾回收机制做以简单的分析,目的是有始有终的交代实例由创建到消亡的全过程。
public static void Main(string[] args)
{
#region 06 垃圾回收的简单阐释
//实例定义及初始化
MyClass mc1 = new MyClass();
//声明但不实体化
MyClass mc2;
//拷贝引用,mc2和mc1指向同一托管地址
mc2 = mc1;
//定义另一实例,并完成初始化
MyClass mc3 = new MyClass();
//引用拷贝,mc1、mc2指向了新的托管地址
//那么原来的地址成为GC回收的对象,在
mc1 = mc3;
mc2 = mc3;
#endregion
}
GC执行时,会遍历所有的托管堆对象,按照一定的递归遍历算法找出所有的可达对象和不可访问对象,显然本示例中的托管堆A对象没有被任何引用访问,属于不可访问对象,将被列入执行垃圾收集的目标。对象由newobj指令产生,到被GC回收是一个复杂的过程,我们期望在系列的后期对此做以深入浅出的理解。
2.7 总结陈述
这些示例主要从从基础的方向入手来剖析前前两回中的探讨,不求能够全面而深邃,但求能够一点而及面的展开,技术的魅力正在于千变万化,技术追求者的力求却是从变化中寻求不变,不然我们实质太累了,我想这就是好方法,本系列希望的就是提供一个入口,打开一个方法。示例的详细分析可以下载[类型示例代码],简单的分析希望能带来丝丝惬意。
3. 结论
值类型和引用类型,要说的,要做的,还有很多。此篇只是一个阶段,更多的深入和探讨我相信还在继续,同时广泛的关注技术力量的成长,是每个人应该进取的空间和道路。
品味类型,为应用之路开辟技术基础。
品味类型,继续探讨还会更多精彩。
------------引用地址:http://blog.csdn.net/netzhou/archive/2007/06/27/1668641.aspx
版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:http://www.cnblogs.com/cyq1162/archive/2007/08/16/858030.html
再聊一次值类型和引用类型 这是一个托管的值类型,表示array的一个片断, 在用做websocket接收数据的载体时我发现每次值传递后, 这个ArraySegment byte 貌似发生了变化。这勾起了我的探究欲。
第183天:引用类型和值类型 一、内存分配 1、数值型内存分配 2 var num1; //这个时候不进行内存分配 3 var num3=9;//分配内存 4 var num4=num3;//会不会分配 6 // 这里到底分配还是不分配内存?? 7 // 答案 --分配内存 彼此拥有独立的内存空间,互不影响 8 console.
c#值类型与引用类型区别 值类型对象的两种表示方式:未装箱和已装箱,引用类型总是处于已装箱 值类型从System.ValueType派生。该类型提供了与System.Object相同方法,但System.ValueType重写了Equals方法, 能在两个对象的自断值完全匹配的前提下返回true。
相关文章
- 返回引用类型的函数指针(c++)
- sqlserver,执行生成脚本时“引发类型为“System.OutOfMemoryException”的异常”(已解决)
- python函数用法详解2(变量的作用域(全局变量、局部变量)、共享全局变量、函数返回值、函数的参数(位置参数、关键字参数、默认参数、不定长参数)、拆包、交换变量值、引用、可变和不可变类型)
- 为BitStruct添加list类型
- C#与 C++数据结构类型对应关系表
- 在C语言中,double、long、unsigned、int、char类型数据所占字节数
- JS的type类型为 text/template
- 引用类型(C# 参考)
- 《JavaScript面向对象精要》——1.3 引用类型
- Java的八种基本类型:(按字节来分)
- Java中gcRoot和引用类型
- c# 引用类型和值类型的内存分配
- 基本引用类型String
- Java魔法堂:四种引用类型、ReferenceQueue和WeakHashMap
- instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例。
- EF 序列化实体为Json时的循环引用问题(不用自己写实体,不用匿名类型,不用EF的上下文属性)
- 值类型和引用类型 区别
- C51数据的存储类型
- C# 引用类型和值类型
- JavaScript引用类型之Array数组的拼接方法-concat()和截取方法-slice()
- JavaScript引用类型之Array数组的toString()和valueof()方法的区别
- C++11 auto自动类型推导
- SQL server int 转char类型