[转] 值类型与引用类型(下)

本文将介绍以下内容:

  • 类型的基本概念
  • 值类型深入
  • 引用类型深入
  • 值类型与引用类型的比较及应用

[下载]:[类型示例代码]

1. 引言

值类型与引用类型的话题经过了两个回合([第八回:品味类型---值类型与引用类型(上)-内存有理]和[第九回:品味类型---值类型与引用类型(中)-规则无边])的讨论和切磋,我们就基本的理解层面来说已经差不多了,但是对这一部分的进一步把握和更深刻的理解还要继续和深化,因为我自己就在两篇发布之际,我就得到装配脑袋兄的不倦指导,之后又查阅了很多的资料发现类型在.NET或者说语言基础中何其重要的内涵和深度,因此关于这个话题的讨论还没有停止,以后我将继续分享自己的所得与所感。

不过作为一个阶段,本文将值类型和引用类型的讨论从应用示例角度来进一步做以延伸,可以看作是对前两回的补充性探讨。我们从类型定义、实例创建、参数传递、类型判等、垃圾回收等几个方面来简要的对上两回的内容做以剖析,并以一定的IL语言和内存机制来说明,期望进一步加深我们的理解和分析。

2. 以代码剖析

下面,我们以一个经典的值类型和引用类型对比的示例来剖析,其区别和实质。在剖析的过程中,我们主要以执行分析(主要是代码注释)、内存分析(主要是图例说明)和IL分析(主要是IL代码简析)三个方面来逐知识点解析,最后再做以总结描述,这样就可以有更深的理解。

2.1 类型定义

定义简单的值类型 MyStruct 和引用类型 MyClass ,在后面的示例中将逐渐完善,完整的代码可以点击下载[类型示例代码]。我们的讨论现在开始,

  • 代码演示
 1     // 01 定义值类型
 2     public struct MyStruct
 3     {
 4         private int _myNo;
 5
 6         public int MyNo
 7         {
 8             get { return _myNo; }
 9             set { _myNo = value; }
10         }
11
12         public MyStruct(int myNo)
13         {
14             _myNo = myNo;
15         }
16
17         public void ShowNo()
18         {
19             Console.WriteLine(_myNo);
20         }
21
22     }
23
24     // 02 定义引用类型
25     public class MyClass
26     {
27         private int _myNo;
28
29         public int MyNo
30         {
31             get { return _myNo; }
32             set { _myNo = value; }
33         }
34
35         public MyClass()
36         {
37             _myNo = 0;
38         }
39
40         public MyClass(int myNo)
41         {
42             _myNo = myNo;
43         }
44
45
46         public void ShowNo()
47         {
48             Console.WriteLine(_myNo);
49         }
50     }
  • IL分析

分析IL代码可知,静态方法.ctor用来表示实现构造方法的定义,其中该段IL代码表示将0赋给字段_myNo。

2.2 创建实例、初始化及赋值

接下来,我们完成实例创建和初始化,和简单的赋值操作,然后在内存和IL分析中发现其实质。

  • 内存实况

首先是值类型和引用类型的定义,这是一切面向对象的开始,

然后是初始化过程,

简单的赋值和拷贝,是最基本的内存操作,不妨看看,

2.3 参数传递

不必多说,就是一个简要阐释,对于参数的传递作者将计划以更多的笔墨来在后面的系列中做以澄清和深入。

2.4 类型转换

类型转换的演示,包括很多个方面,在此我们只以自定义类型转换为例来做以说明,更详细的类型转换可以参考[第九回:品味类型---值类型与引用类型(中)-规则无边]的[再论类型转换部分]。

  • 代码演示

首先是值类型的自定义类型转换,

1     public struct MyStruct
2     {
3         // 01.2 自定义类型转:整形->MyStruct型
4         static public explicit operator MyStruct(int myNo)
5         {
6             return new MyStruct(myNo);
7         }
8     }

然后是引用类型的自定义类型转换,

 1    public class MyClass
 2     {
 3         // 02.2 自定义类型转换:MyClass->string型
 4         static public implicit operator string(MyClass mc)
 5         {
 6             return mc.ToString();
 7         }
 8
 9         public override string ToString()
10         {
11             return _myNo.ToString();
12         }
13     }

最后,我们对自定义的类型做以测试,

 1         public static void Main(string[] args)
 2         {
 3             #region 03. 类型转换
 4             MyStruct MyNum;
 5             int i = 100;
 6             MyNum = (MyStruct)i;
 7             Console.WriteLine("整形显式转换为MyStruct型---");
 8             Console.WriteLine(i);
 9
10             MyClass MyCls = new MyClass(200);
11             string str = MyCls;
12             Console.WriteLine("MyClass型隐式转换为string型---");
13             Console.WriteLine(str);
14             #endregion
15          }       

2.5 类型判等

类型判等主要包括:ReferenceEquals()、Equals()虚方法和静态方法、==操作符等方面,同时注意在值类型和引用类型判等时的不同之处,可以参考[第九回:品味类型---值类型与引用类型(中)-规则无边]的[4. 再论类型判等]的简述。

  • 代码演示
 1 // 01 定义值类型
 2 public struct MyStruct
 3 {
 4
 5 // 01.1 值类型的类型判等
 6 public override bool Equals(object obj)
 7 {
 8 return base.Equals(obj);
 9 }
10
11 }
12
13 public class MyClass
14 {
15
16 // 02.1 引用类型的类型判等
17 public override bool Equals(object obj)
18 {
19 return base.Equals(obj);
20 }
21
22 }
23
24 public static void Main(string[] args)
25
26 {
27
28 #region 05 类型判等
29 Console.WriteLine("类型判等---");
30 // 05.1 ReferenceEquals判等
31 //值类型总是返回false,经过两次装箱的myStruct不可能指向同一地址
32 Console.WriteLine(ReferenceEquals(myStruct, myStruct));
33 //同一引用类型对象,将指向同样的内存地址
34 Console.WriteLine(ReferenceEquals(myClass, myClass));
35 //RefenceEquals认为null等于null,因此返回true
36 Console.WriteLine(ReferenceEquals(null, null));
37
38 // 05.2 Equals判等
39 //重载的值类型判等方法,成员大小不同
40 Console.WriteLine(myStruct.Equals(myStruct2)) ;
41
42 //重载的引用类型判等方法,指向引用相同
43 Console.WriteLine(myClass.Equals(myClass2));
44
45 #endregion
46
47 }  

2.6 垃圾回收

首先,垃圾回收机制,绝对不是三言两语就能交代清楚,分析明白的。因此,本示例只是从最简单的说明出发,对垃圾回收机制做以简单的分析,目的是有始有终的交代实例由创建到消亡的全过程。

  • 代码演示
 1 public static void Main(string[] args)
 2 {
 3
 4 #region 06 垃圾回收的简单阐释
 5 //实例定义及初始化
 6 MyClass mc1 = new MyClass();
 7 //声明但不实体化
 8 MyClass mc2;
 9 //拷贝引用,mc2和mc1指向同一托管地址
10 mc2 = mc1;
11 //定义另一实例,并完成初始化
12 MyClass mc3 = new MyClass();
13 //引用拷贝,mc1、mc2指向了新的托管地址
14 //那么原来的地址成为GC回收的对象,在
15 mc1 = mc3;
16 mc2 = mc3;
17 #endregion
18
19 }  
  • 内存实况

GC执行时,会遍历所有的托管堆对象,按照一定的递归遍历算法找出所有的可达对象和不可访问对象,显然本示例中的托管堆A对象没有被任何引用访问,属于不可访问对象,将被列入执行垃圾收集的目标。对象由newobj指令产生,到被GC回收是一个复杂的过程,我们期望在系列的后期对此做以深入浅出的理解。

2.7 总结陈述

这些示例主要从从基础的方向入手来剖析前前两回中的探讨,不求能够全面而深邃,但求能够一点而及面的展开,技术的魅力正在于千变万化,技术追求者的力求却是从变化中寻求不变,不然我们实质太累了,我想这就是好方法,本系列希望的就是提供一个入口,打开一个方法。示例的详细分析可以下载[类型示例代码],简单的分析希望能带来丝丝惬意。

3. 结论

值类型和引用类型,要说的,要做的,还有很多。此篇只是一个阶段,更多的深入和探讨我相信还在继续,同时广泛的关注技术力量的成长,是每个人应该进取的空间和道路。

品味类型,为应用之路开辟技术基础。

品味类型,继续探讨还会更多精彩。
------------引用地址:http://blog.csdn.net/netzhou/archive/2007/06/27/1668641.aspx

时间: 2024-10-05 22:31:19

[转] 值类型与引用类型(下)的相关文章

【转】C#详解值类型和引用类型区别

通用类型系统 值类型 引用类型 值类型和引用类型在内存中的部署 1 数组 2 类型嵌套 辨明值类型和引用类型的使用场合 5 值类型和引用类型的区别小结 首先,什么是值类型,什么是引用类型? 在C#中值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中. 值类型(value type):byte,short,int,long,float,double,decimal,char,bool 和 struct 统称为值类型.值类型变量声明后,不管是否已经赋值,编译器为其分配内

C# 类型基础 值类型和引用类型

引言 本文之初的目的是讲述设计模式中的 Prototype(原型)模式,但是如果想较清楚地弄明白这个模式,需要了解对象克隆(Object Clone),Clone其实也就是对象复制.复制又分为了浅度复制(Shallow Copy)和深度复制(Deep Copy),浅度复制和深度复制又是以如何复制引用类型成员来划分的.由此又引出了引用类型和值类型,以及相关的对象判等.装箱.拆箱等基础知识.索性从最基础的类型开始自底向上写起. 值类型和引用类型 先简单回顾一下C#中的类型系统.C# 中的类型一共分为

20151024_001_C#基础知识(静态与非静态的区别,值类型和引用类型,堆和栈的区别,字符串的不可变性,命名空间)

1:我们把这些具有相同属性和相同方法的对象进行进一步的封装,抽象出来类这个概念. 类就是个模子,确定了对象应该具有的属性和方法. 对象是根据类创建出来的. 2:类:语法 [public] class 类名 { 字段; 属性; 方法; } 写好了一个类之后,我们需要创建这个类的对象,那么,我们管创建这个类的对象过程称之为类的实例化.使用关键字new 实例化类===创建类 this:表示当前这个类的对象. 类是不占内存的,而对象是占用内存的. 结构是面向过程的,类是面向对象的,之前没有面向对象的时候

C#值类型和引用类型用C语言理解

我刚用C#一个来月,可能理解得不对,还请大家指教. 读懂文章你需要对C语言的指针有所理解. 需要注意区别:对C\C++来说,任何类型都可以当成C#的"引用类型",因为有指针. [在内存上] void foo() { int aaa = 0; //值类型,aaa在Stack上分配(SUB ESP,XX) int* paaa = new int[123]; //引用类型,paaa在Heap上分配,HeapAlloc(GetProcessHeap()...) foo2(&aaa);

交换两个数值(值类型,引用类型)

变量可以理解为一块空间,int类型变量,就是创建4个字节单位的空间.一块空间单位,只能存取一个值. 值类型交换数字的方法.首先说一下,值类型:值类型就是存在栈上的.简单的理解下,内存是怎么样分配的呢,静态存储区,就是在程序编译的时候,内存就已经分配好了的,并且存在周期是程序的整个运行周期,全局变量,静态变量等.栈上分配:其实也是在程序的运行的时候,可以分配固定太小的内存,并且可以由操作系统自动回收的功能.既然,值类型,引用类型,我觉得值类型存在的必要是什么,什么都是以对象来实现的,不存在值类型,

c#值类型和引用类型

值类型值类型的特性:1.C#的所有值类型均隐式派生自System.ValueType.各个值类型及其基类:结构体:struct(直接派生于System.ValueType):数值类型:整型:short(System.Int16),ushort(System.UInt16),int(System.Int32),uint(System.UInt32),long(System.Int64),ulong(System.UInt64),sbyte(System.SByte的别名),byte(System.

数往知来C#之接口 值类型与引用类型 静态非静态 异常处理 GC垃圾回收 值类型引用类型内存分配<四>

C# 基础接口篇 一.多态复习 使用个new来实现,使用virtual与override    -->new隐藏父类方法 根据当前类型,电泳对应的方法(成员)    -->override重写 无论什么情况,都是执行新的方法(成员) 继承是实现多态的一个前提,没有继承多态是不能实现的 父类与子类实现多态 抽象类与子类实现 抽象类不能实例化 抽象类中的抽象方法没有方法体 抽象类的成员有哪些   ->包含非抽象成员   ->不能实例化   ->子类必须实现父类的 抽象方法,除非子

6个重要的.NET概念栈,堆,值类型,引用类型,装箱,拆箱

介绍 这篇文章将解释6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱.本文将会阐述当你声明一个变量时发生了什么并提前说明两个重要个概念:栈和堆.文章将围绕引用类型和值类型澄清一些重要基本信息.并通过一个简单的示例来演示装箱和拆箱引起的性能损失. 声明一个变量时发生了什么? 当你在.NET应用程序中声明了一个变量时,将会从RAM中分配一小块内存,在内存中存在三样东西:变量名称,数据类型和变量的值. 我们简单的说明下在内存中发生了什么,要知道变量在内存中的分配是取决于数据类型的.这里存在两种类型

C#学习笔记(三):值类型、引用类型及参数传递

值类型和引用类型简介 C#中存在两种数据类型,分别是值类型与引用类型,下面我们来看看这两种类型的区别. 值类型主要包括: 简单类型(如int.float.char等,注意string不是值类型): 枚举类型(enum): 结构体类型(struct): 引用类型主要包括: 类类型(如string): 数组类型(一维或多维数组): 接口类型(interface): 委托类型(delegate): 内存分布 值类型的实例大部分情况下会被存放在线程的堆栈上,由操作系统管理其在内存上的分配和释放. 引用类