值类型与引用类型(下)

本文将介绍以下内容:

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

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

 

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();
        }
    }

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

        public static void Main(string[] args)
        {          
            #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. 结论

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

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

品味类型,继续探讨还会更多精彩。

时间: 2024-08-01 20:10:41

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

[你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途

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

值类型与引用类型(中)

本文将介绍以下内容: 类型的基本概念  值类型深入 引用类型深入 值类型与引用类型的比较及应用    1. 引言 上回[第八回:品味类型---值类型与引用类型(上)-内存有理]的发布,受到大家的不少关注,我们从内存的角度了解了值类型和引用类型的所以然,留下的任务当然是如何应用类型的不同特点在系统设计.性能优化等方面发挥其作用.因此,本回是对上回有力的补充,同时应朋友的希望,我们尽力从内存调试的角度来着眼一些设计的分析,这样就有助于对这一主题进行透彻和全面的理解,当然这也是下一回的重点. 从内存角

Emit学习-答疑篇-值类型和引用类型在使用时的区别

今天下午兴冲冲的写完一段IL代码,用Reflector转成C#代码看了下,没有问 题,于是引用持久化到硬盘上的动态程序集,想要试一下其中的方法,但是运行 后却出现了System.AccessViolationException,提示信息为:"尝试读取或写入 受保护的内存.这通常指示其他内存已损坏.".看着错误提示一阵头大,新配 的电脑内存损坏是不太可能了,只好从自己的程序中找原因. 经过一阵调试,终于找到了引发异常的地方,是在构造函数中用 DateTime.Now.Millisecon

[你必须知道的.NET]第九回:品味类型---值类型与引用类型(中)-规则无边

本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 1.引言 上回[第八回:品味类型---值类型与引用类型(上)-内存有理]的发布,受到大家的不少关注,我们从内存的角度了解了值类型和引用类型的所以然,留下的任务当然是如何应用类型的不同特点在系统设计.性能优化等方面发挥其作用.因此,本回是对上回有力的补充,同时应朋友的希望,我们尽力从内存调试的角度来着眼一些设计的分析,这样就有助于对这一主题进行透彻和全面的理解,当然这也是下一回的重点. 从内存角度来讨论值

Swift里的值类型与引用类型区别和使用

  这篇文章主要介绍了Swift里的值类型与引用类型区别和使用,本文讲解了值类型与引用类型的区别.如何选择类型.什么时候该用值类型.什么时候该用引用类型等内容,需要的朋友可以参考下 Swift里面的类型分为两种: ●值类型(Value Types):每个实例都保留了一分独有的数据拷贝,一般以结构体 (struct).枚举(enum) 或者元组(tuple)的形式出现. ●引用类型(Reference Type):每个实例共享同一份数据来源,一般以类(class)的形式出现. 在这篇博文里面,我们

深入理解PHP变量的值类型和引用类型_php实例

在PHP中,大部分变量类型,如字符串,整型,浮点,数组等都是值类型的,而类和对象是引用类型,在使用的时候,需要注意这一点. 看到网友在讨论PHP的&符号,要彻底理解它的用法,就有必要讨论一下变量的两种形式. PHP的变量在内存中是这样存储的,变量保存的并不直接是值的内容,而是地址.例如: $a = 1; 我们看起来,似乎变量$a直接存储了 1 这个值.而实际情况是,PHP解释器创建了变量$a,将值:1 存入内存中的某个地方,再将值的地址存到变量$a中. 需要取值时,先找到变量$a中的地址,再根据

asp.net c# 值类型与引用类型详细说明

asp教程.net c# 值类型与引用类型详细说明 c# 中的类型有两种:值类型 (value type) 和引用类型 (reference type). 值类型的变量直接包含它们的数据,而引用类型的变量存储对它们的数据的引用,后者称为对象. 对于引用类型,两个变量可能引用同一个对象,因此对一个变量的操作可能影响另一个变量所引用的对象. 对于值类型,每个变量都有它们自己的数据副本(除 ref 和 out 参数变量外),因此对一个变量的操作不可能影响另一个变量. c# 的值类型进一步划分为简单类型

c 值类型和引用类型详解

非引用形参通过用实参的副本初始化形参,修改形参的值,不会影响实参的值,然而复制实参并不是在所有的情况下都适合,不适宜复制实参的情况包括: l 当需要在函数中修改实参的值时 l 当需要以大型对象作为实参传递时.对实际的应用而言,复制对象所付出的时间和存储空间代价往往过大 l 当没有办法实现实参的复制时. 对第一种情况很常见,而第二种情况,则是为了性能必须要考虑进去的,比如下面的一段程序,就把形参用成了引用类型,是因为我这个程序是要把ifstream的内容复制到vector中,然而ifstream读

Swift里的值类型与引用类型区别和使用_Swift

Swift里面的类型分为两种: ●值类型(Value Types):每个实例都保留了一分独有的数据拷贝,一般以结构体 (struct).枚举(enum) 或者元组(tuple)的形式出现. ●引用类型(Reference Type):每个实例共享同一份数据来源,一般以类(class)的形式出现. 在这篇博文里面,我们会介绍两种类型各自的优点,以及应该怎么选择使用. 值类型与引用类型的区别 值类型和引用类型最基本的分别在复制之后的结果.当一个值类型被复制的时候,相当于创造了一个完全独立的实例,这个