当前位置: 首页 > news >正文

C# 值类型和引用类型

一、基本概念

C#只有两种数据类型:值类型和引用类型

值类型在线程栈分配空间,引用类型在托管堆分配空间

值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱

以下是值类型和引用类型对照表

从上图可以简单看出:string,Object,数组,class是引用类型,简单类型,枚举,结构是值类型。

二、代码展示

定义一个类和结构调用赋值

内存分配情况如下图:

从这张图可以看出,class实例化出来的对象,指向了内存堆中分配的空间;truct实例化出来的对象,是在内存栈中分配。

修改代码如下:

内存分配情况:

由上图可以知:

object obj=”abc”;  
string i=(string)obj;  

值类型和引用类型储的位置不一样
如果是引用类型,当两个对象指向同一个地方,修改某一个的时候,其它对象的值会发生改变

注意点:

1、值类型变量做为局部变量时,该实例将被创建在堆栈上;而如果值类型变量作为类型的成员变量时,它将作为类型实例数据的一部分,同该类型的其他字段都保存在托管堆上。

2、引用类型变量数据保存在托管堆上,但是根据实例的大小有所区别:当实例的大小小于85000Byte时实例将创建在GC堆上;当实例大小>=85000byte时,则该实例创建在LOH(Large Object Heap)堆上。

using System;

namespace ConsoleApplication2
{
    //引用类型(因为‘class’)
    public class SomeRef
    {
        public int x { get; set; }
    }
    //值类型(因为‘struct’)
    public struct SomeVal
    {
        public int x{ get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SomeRef r1=new SomeRef();  //在堆上分配
            SomeVal v1 = new SomeVal();//在栈上分配
            r1.x = 5;       //提领指针
            v1.x = 5;       //在栈上修改
            Console.WriteLine(r1.x); //显示5  
            Console.WriteLine(v1.x); //显示5

            SomeRef r2 =r1;  //只复制引用(指针)
            SomeVal v2 =v1;  //在栈上分配并赋值成员
            r1.x = 8;       //r1.x和r2.x都会修改
            v1.x = 8;       //v1.x会更改,v2.x不会

            Console.WriteLine(r1.x); //显示8  
            Console.WriteLine(r2.x); //显示8  
            Console.WriteLine(v1.x); //显示8
            Console.WriteLine(v2.x); //显示5

            Console.ReadKey();
        }
    }
}
图片上的代码

 

二、值类型装箱、拆箱

1、装箱:就是将值类型的数据打包到引用类型的实例中( 比如将int类型的值1赋给object对象obj)

int  i=1;  
object obj=(object)i;  

 装箱时到底发生的事情:

1)、在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上托管堆所有对象都有的两个额外成员(类型对象指针和同步块索引)所需的内存量

2)、值类型的字段复制到新分配的堆内存

3)、返回对象地址,现在该地址是对象引用;值类型成了引用类型

2、拆箱:就是从引用数据中提取值类型(比如将object对象obj的值赋给int类型的变量i)

object obj=”1”;  
int i=(int)obj;  

拆箱不是装箱过程倒过来,拆箱的代价要比装箱低的多,拆箱是获取指针的过程,该指针指向包含在一个对象中的原始值类型。

拆箱后将堆中的字段包含的值复制栈的值类型实例中。

3、值类型变为引用类型不一定要装箱,例如:

string str = "joye.net" + 26;   //需要将26装箱为string类型
string str1 = "joye.net" + 26.ToString(); //tostring后不需要装箱

感兴趣的可以用IL看一下。

三、参考资料

  《深入理解C#》第二版

  《CLR VIA C#》第四版

  《C# 高级编程》第四版

  还有很多网络上的文章,就不一一例举了

转载于:https://www.cnblogs.com/yinrq/p/5588330.html

相关文章:

  • mysql悲观锁以及乐观锁总结和实践
  • 自制WheelView沉浸式菜单及Dialog样式Activity
  • mvc ajax提交数组参数(转)
  • Git相关命令
  • javascript基础总结
  • 组策略应用——限制计算机接入
  • 创建swap
  • JavaScript语法详解(一)
  • 二分搜索法 Arrays.binarySearch遇到返回-1的问题
  • gitlab gerrit jenkins CI/CD环境集成
  • 开发者和程序员需要关注的42个播客
  • C库数学函数
  • 关于QT下资源使用和资源占用…
  • ASP.Net MVC开发基础学习笔记(1):走向MVC模式
  • 使用JDBC处理LOB大型对象
  • 分享一款快速APP功能测试工具
  • 【comparator, comparable】小总结
  • 【前端学习】-粗谈选择器
  • co.js - 让异步代码同步化
  • Gradle 5.0 正式版发布
  • java8-模拟hadoop
  • JavaScript中的对象个人分享
  • JS数组方法汇总
  • Mybatis初体验
  • 闭包,sync使用细节
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 从零开始在ubuntu上搭建node开发环境
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 动态规划入门(以爬楼梯为例)
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 机器学习 vs. 深度学习
  • 基于HAProxy的高性能缓存服务器nuster
  • 解析带emoji和链接的聊天系统消息
  • 蓝海存储开关机注意事项总结
  • 力扣(LeetCode)21
  • 项目实战-Api的解决方案
  • 走向全栈之MongoDB的使用
  • NLPIR智能语义技术让大数据挖掘更简单
  • #每天一道面试题# 什么是MySQL的回表查询
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (C#)获取字符编码的类
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (动态规划)5. 最长回文子串 java解决
  • (图)IntelliTrace Tools 跟踪云端程序
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • .gitignore
  • .net core使用ef 6
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • /etc/fstab 只读无法修改的解决办法
  • @RequestBody与@ModelAttribute
  • @我的前任是个极品 微博分析