zoukankan      html  css  js  c++  java
  • C#值类型和引用类型

    资料:《Learning hard C#学习笔记》李志

    值类型:

      1.包含类型:

        简单类型:int,long,short,sbyte,uint,ulong,ushort,byte,char,float,double,decimal,bool

        枚举类型:enum

        结构体类型:struct

        

    引用类型:

      1.包含类型:

         类类型:string,Console类和自定义类

        数组类型:一维数组,多维数组

        接口类型:interface

        委托类型:delegate

     

     

    值类型和引用类型的区别:

      1.值类型分配在线程堆栈上(管理由操作系统负责),引用类型分配在托管堆上(管理由垃圾回收器GC负责)。管理指内存空间的分配和释放

        1)变量本身是存储在堆栈上的(无论是值类型变量还是引用类型变量)

        2)但是对于实际数据:引用类型存在托管堆上,值类型存在堆栈

      2.值类型继承自valueType,valueType继承自System.Object;引用类型直接继承自System.Object

      3.值类型在作用域内结束时,会被操作系统自释放,减少托管堆压力;引用类型则靠GC。因此值类型在性能上由优势

      4.值类型是密封的,不能作为基类。引用类型一般具有继承性

      5.值类型不能为null,默认初始化为该类型的默认值;引用类型默认初始化为null

      6.值类型作为参数传递时,不影响本身。引用类型作为参数传递时,会改变最终该变量的值

     

    装箱:值类型转为引用类型

      步骤:

        1)内存分配:在托管堆分配内存空间

        2)实际数据的复制:将值类型的数据复制到新分配的内存中

        3)地址返回

    拆箱:引用类型转为值类型

      步骤:

        1)检查实例:引用类型是否为Null?不为Null那和拆箱后的类型是否是同一类型

        2)地址返回

        3)数据复制:堆数据复制到栈

    装箱和拆箱都会对数据进行复制,所以会影响性能。最好使用泛型编程

     

    在方法的形参操作中,值类型调用方法后不会更改原数据的值,引用类型则会更改数据的值。但是引用类型的string是具有不可变性的,例如在形参传递string类型的数据,该方式通过重新分配一个新的空间存储新数据实现的。

     

    无论值类型还是引用类型,都可以通过ref,out关键字实现引用传递。这样就解决了返回多个值问题

     

     public IActionResult Index()
            {
                ValueTypeAndRefType newType = new ValueTypeAndRefType();
                int age = 6;
                newType.changeByValue(ref age);//age:100
                string name = "zs";
                newType.changeByRef(ref name);
                ViewBag.Cat66 = name;//name:abc 实际上因为string不可变,也是开辟了新的空间,只是把name的指向改成了新的变量指向
            
                return View();
            }
    

     

        public class ValueTypeAndRefType //类是引用类型,通过调用类,再去改里面的值,那么该实例化类的该值也会被改掉
        {
            public int valueType = 3;
    
            public int method()
            {
                int age = 10;//堆栈
    
                isValueType(age);
                return age; //10
            }
    
            public void isValueType(int val)
            {
                val = 20;
            }
    
            public void changeByValue(ref int val)
            {
                val = 100;
            }
            public void changeByRef(ref string val)
            {
                val = "abc";
            }
        }  

      

     

    ref和out的区别:

        ref的参数必须在方法外初始化,out的参数在方法内必须赋值

    重载是不看ref和out的,背后的编译是一样的

     

     

    is和as类型转换:(转换类型最好通过is,as判断,因为强制转换会抛出异常)

      is用来判断类型是否可以转换(引用类型转换,装箱,拆箱)

      as是两个引用之间进行转换,成功则赋值,不成功则返回null

     

                //is,as
                object o = new object();
                if (o is int)//引用类型转换,装箱,拆箱
                {
                    ViewBag.Cat66 = "yes";
                }
                else
                {
                    ViewBag.Cat66 = "no";
                }
    
                string n = null;
                object m = n as object;//两个引用之间进行转换
                if (m == null)
                {
                    ViewBag.Cat66 = "no";
                }
                else
                {
                    ViewBag.Cat66 = m;
                }
    

      

  • 相关阅读:
    今天博客开通第一天,以此纪念!
    基于opencv的车牌识别系统
    【C和指针】笔记1
    【局域网聊天客户端篇】基于socket与Qt
    对Qt下对话服务器客户端的总结(MyTcpServer与MyTcpClient)
    linux 线程编程详解
    【linux】安装samba服务
    linux(ubuntu)获取命令源码方式
    win7下用SSH连接linux虚拟机
    Linux下deb包安装工具(附带安装搜狗输入法)
  • 原文地址:https://www.cnblogs.com/cat66/p/11130728.html
Copyright © 2011-2022 走看看