C#基础知识整理 基础知识(19) 值类型的装箱和拆箱(二)

如果代码中会造成编译器的反复装箱,可改为手动装箱,这样来使代码执行更快,看下面代码:

            //手动装箱            Int32 v = 5;            //由于string.Format的参数是object类型,所以这里会造成三次装箱。            Console.WriteLine(string.Format("{0},{1},{2}", v, v, v));            //修改一下,当然这只是一个小技巧,比如程序中对同一个值的同一个操作执行多次,            //应该都是要先执行一次,然后再使用的。            Object o = v;//装箱一次            Console.WriteLine(string.Format("{0},{1},{2}", o, o, o));

通过前面的代码段,我们再写程序时就很容易判断什么时候值类型要装箱。无非就是当要获取一个值类型的引用时,就要装箱。这里也很清楚的可以看出值类型与引用类型的区别:
1、值类型不在托管堆中分配空间;而引用类型在实例化后就在堆上分配了类中指定的成员的的空间。
2、值类型没有堆上的对象的额外成员,即“类型对象指针”、“同步索引”。
未装箱的值类型没有同步索引,因此不能使用该类型所在类的方法(比如lock)让多个线程同步对这个实例的访问。
虽然未装箱的值类型没有类型对象指针,但仍可调用由类型继承或重写的虚方法,比如Equals,GetHashCode,ToString。如果值类型重写了其中任何一个虚方法,那么CLR可以非虚地调用该方法,因为值类型是隐式密封的,没有任何类型能够从它派生。此外,用于调用虚方法的值类型实例不会被装箱。如果重写的虚方法要调用方法在基类中的实现,那么在调用基类的实现时,值类型实例会装箱。因为这些方法是有System.Object定义的,所以这些方法期望this实参是指向堆上的一个对象的指针。
此外,将值类型的一个未装箱实例转型为类型的某个接口是,要求实例进行装箱。因为接口变量必须包含对堆上的一个对象的引用。看下面代码:
 

 class Program    {        static void Main(string[] args)        {            Point p1 = new Point(10, 10);            Point p2 = new Point(20, 20);            //调用ToString不装箱,这里ToString是一个虚方法            Console.WriteLine(p1.ToString());            //GetType是一个非虚方法,p1要装箱            Console.WriteLine(p1.GetType());            //这里调用的是public int CompareTo(Point p)            //p2不会装箱            Console.WriteLine(p1.CompareTo(p2));            //p1要装箱,这就是将未装箱的值类型转为类型的某个接口时            IComparable c = p1;            Console.WriteLine(c.GetType());            //这里调用的是public Int32 CompareTo(Object o),            //而且c本来就是一个引用,因此不装箱了            Console.WriteLine(p1.CompareTo(c));            //这里调用的是c的CompareTo方法,参数是object型的            //所以要对p2装箱            Console.WriteLine(c.CompareTo(p2));            //对c拆箱,并复制值到p2中            p2 = (Point)c;            Console.WriteLine(p2.ToString());        }    }         internal struct Point : IComparable    {        private Int32 x;        private Int32 y;        public Point(Int32 x, Int32 y)        {            this.x = x;            this.y = y;        }        public override string ToString()        {            return string.Format("{0},{1}", x, y);//这里装箱两次,不知道有没好办法。        }        public int CompareTo(Point p)        {            return Math.Sign(Math.Sqrt(x * x + y * y) - Math.Sqrt(p.x * p.x + p.y * p.y));        }        public Int32 CompareTo(Object o)        {            if (GetType() != o.GetType())            {                throw new ArgumentException("o is not Point.");            }            return CompareTo((Point)o);        }    }

以上就是C#基础知识整理 基础知识(19) 值类型的装箱和拆箱(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1432245.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月17日 06:23:58
下一篇 2025年12月15日 09:26:07

相关推荐

  • C#基础知识整理 基础知识(20) 委托(一)

    委托和事件在c#中使用很多,尤其在进行窗体编程时,很多的操作都要通过委托和事件来处理和传递。这里详细解释下委托和事件的用法和原因,使我们在写代码时能更加明白一些。委托的使用事件是一种机制,事件是通过委托实现的,所以看明白了委托,对于事件也就能更好的理解了。先看下面一个小例子。这是描述不同语言的程序员…

    2025年12月17日
    000
  • C#基础知识整理 基础知识(21) 委托(二)

    看了前面一篇委托的用法中http://www.php.cn/,我们看到, public void Description(string programerName, DescriptionDelegate description) { description(programerName); } 这个…

    2025年12月17日
    000
  • C# 使用绑定句柄来减少进程的内存耗用

    许多应用程序中,绑定了一组类型(type)或者类型成员(从memberinfo派生),并将这些对象保存在某种形式的一个集合中。以后,会搜索这个集合,查找特定的对象,然后调用这个对象。这是一个很好的机制,但是有个小问题:type和memberinfo派生的对象需要大量的内存。如果一个应用程序容纳了太多…

    好文分享 2025年12月17日
    000
  • C# 反射详解

    以上就是C# 反射详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!

    2025年12月17日
    000
  • C# 清除事件绑定的函数

    c#  清除事件绑定的函数 #region 清除事件绑定的函数 /// /// 清除事件绑定的函数 /// /// 拥有事件的实例 /// 事件名称 public static void ClearAllEvents(object objectHasEvents, string eventName)…

    好文分享 2025年12月17日
    000
  • C#中Encoding.Unicode与Encoding.UTF8的区别

    原文地址:点击打开链接 今天在园子首页看到一篇博文-简单聊下Unicode和UTF-8,从中知道了UTF-8是Unicode的一种实现方式: Unicode只是给这世界上每个字符规定了一个统一的二进制编号,并没有规定程序该如何去存储和解析。 可以说UTF-8是Unicode实现方式之一……

    2025年12月17日
    000
  • C# Protobuf-Net 序列化

    源码位置:protobuf-net 1、安装Nuget : 工具–拓展管理器 安装完成后重启Microsoft Visual Studio 2010,可以看到下图: 小注: 只有该解决方案已经打开项目的时候,才会看到下面两项: 2、安装protobuf_net(在Nuget中找到prot…

    2025年12月17日 好文分享
    000
  • C# 文件流压缩解压

    /// /// 文件流压缩解压 /// public class ZipHelper { public static int BEST_COMPRESSION = 9; public static int BEST_SPEED = 1; public static int DEFAULT_COMPR…

    好文分享 2025年12月17日
    000
  • C# DataSet性能最佳实践

    c# 性能优化细节 1、使用ItemArray实现对DataRow的批量赋值 在对DataRow的所有字段赋值时,使用字段名进行逐列赋值效率较低。这时应尽量使用批量字段赋值。可以使用ItemArray或rows.Add方法: / ds是数据集(DataSet)对象DataTable dt = ds.…

    好文分享 2025年12月17日
    000
  • C# 字符串操作–减少垃圾回收压力

    c# 性能优化细节 1、使用string.Empty给一个空字符串变量赋初始值 String.Empty是一个指代,而””是具体的实现 string filter=“”;//不建议 string filter=string.Empty; //建议 2、使用str.Length == 0做空串比较 最…

    好文分享 2025年12月17日
    000
  • C# 异常处理(Catch Throw)IL分析

    1、catch throw的几种形式及性能影响: private void Form1_Click(object sender, EventArgs e) { try { } catch { throw; } } private void Form1_Load(object sender, Even…

    2025年12月17日
    000
  • C# SQLite数据库 访问封装类

    在客户端配置文件节点下,添加: 其中【localdb】是本地SQLite数据库的名称,【config/local.db】是在当前程序运行目录下SQLite数据库位置 C# SQLite数据库  访问封装类代码: /// /// 本类为SQLite数据库帮助静态类,使用时只需直接调用即可,无需实例化 …

    好文分享 2025年12月17日
    000
  • C# DataRow 比较

    /// /// dataRow比较 /// /// /// /// 需要比较的列名称 /// public static bool DataRowCompare(DataRow drA, DataRow drB, string[] columnNames) { bool flag = false; …

    好文分享 2025年12月17日
    000
  • C#基础知识整理:基础知识(5) 方法的重载

        老师都有讲课这个方法,一个老师先是在西部偏远山区,是站在教室里木头的黑板前讲课;过了几年表现好,调到了稍微好点的城市里,是坐在教室前用多媒体设备讲课;又过了几年考博士了,毕业后继续当老师,不过现在是躺在家里对着电脑远程授课。都是讲课这个方法,不同的条件下(参数不同)有不同的执行过程和输出结果…

    2025年12月17日
    000
  • C#基础知识整理:基础知识(6) 抽象类和抽象方法

    在实际项目中,当我们设计一个父类时,经常会遇到这个类不能确定它的具体执行流程的。比如我设计一个文件类: public class AFile { private string name = string.Empty; private string path = string.Empty; priva…

    好文分享 2025年12月17日
    000
  • C#基础知识整理:基础知识(7) 方法的隐藏

    继承和抽象类中提到过,子类与父类的方法间有这些关系:子类直接使用父类方法(但是必须父类方法是public或protected类型);子类的方法覆盖父类方法(override);子类的方法重载父类方法(overload);看下面这种情况: public class YSchool { private …

    2025年12月17日
    000
  • C#基础知识整理:基础知识(8) 接口

        前面接触了抽象类,它的特点是子类必须实现abstract修饰的方法。以及还有virtual修饰的方法,virtual修饰的方法子类可以重写也可以不重写而直接使用。但是由于c#也是单继承的,所以定义一个父类,然后继承来扩展一些类的时候,会遇到不合适的情况。因为我们程序员是用程序语言来描述世界的…

    好文分享 2025年12月17日
    000
  • C#基础知识整理:基础知识(9) 接口的应用

        前面接触过接口的概念,其实接口就是一组方法、属性,然后谁继承了它,谁就要实现这组方法和属性。也就是说这个类具备了这个接口定义的一些能力。    接口的这种特性在平常的程序编写中是有很大作用的,往往完成一个大项目需要很多人同时完成,这样难免会有一些类都需要某些方法,而且执行流程都差不多。这是在…

    2025年12月17日
    000
  • C#基础知识整理:基础知识(10) 静态

        如果想访问某个类的方法或属性,一定要先实例化该类,然后用该类的对象加.号访问。比如:有一个用户类和一个处理密码(加密和解密)的类。没生成一个用户实例后,处理密码类要对密码进行加密和解密。 using System;using System.Collections.Generic;using …

    2025年12月17日
    000
  • C#基础知识整理:基础知识(11) 值类型,引用类型

    c#是面向对象的语言,在面向对象的思想中,只有对象,所有事物都可以用类描述。所以比如这些,int,bool,char,string,double,long等都是类,那么像,30,2.5,”test”都是对应类的一个对象。 static void Main(string[] a…

    2025年12月17日
    000

发表回复

登录后才能评论
关注微信