装箱与拆箱C#(三)之避免拆箱

struct Angle:IAngle
    {
        private int _Hours;
        private int _Minutes;
        private int _Seconds;
        public int Hours
        {
            get { return _Hours; }
        }
        public int Minutes
        {
            get { return _Minutes; }
        }
        public int Seconds
        {
            get { return _Seconds; }
        }
        public Angle(int hours,int minutes,int seconds)
        {
            _Hours = hours;
            _Minutes = minutes;
            _Seconds = seconds;
        }
        public Angle(int hours,int minutes):this(hours,minutes,default(int))
        {

        }
        public Angle Move(int hours,int minutes,int seconds)
        {
            return new Angle(Hours + hours, minutes + Minutes, seconds + Seconds);
        }
        public void MoveTo(int hours,int minutes,int seconds)
        {
            _Hours = hours;
            _Minutes = minutes;
            _Seconds = seconds;
        }

    }

interface IAngle
    {
        void MoveTo(int hours, int minutes, int seconds);
    }


    class Program
    {static void Main(string[] args)
        {
            Angle angle = new Angle(25, 58, 23);
            object objectAngle = angle;//装箱,值类型付给引用类型
            Console.Write(((Angle)objectAngle).Hours);//print 25  拆箱

            ((Angle)objectAngle).MoveTo(26, 58, 23);//修改值,为了调用MoveTo需将objectAngle拆箱并创建一个值的副本。虽然栈值改变、但会被丢弃 ,在objectAngle引用堆不发生改变
            Console.Write(", " + ((Angle)objectAngle).Hours);//print 25

            ((IAngle)angle).MoveTo(26, 58, 23);//值被转型为接口IAngle变量,即发生装箱,运行时将angle数据复制到堆上,在调用返回前会在堆上操作,结果不会发生从堆到栈的复制。相反修改过得堆数据准备好进行垃圾回收,而angle中的数据保持未更改状态
            Console.Write(", " + ((Angle)angle).Hours);// print  25

            ((IAngle)objectAngle).MoveTo(26, 58, 23);//向IAngle转型不发生复制动作,即两个引用型不发生装箱操作 ,更新Hours的值会改变
            Console.Write(", " + ((Angle)objectAngle).Hours);//print 26
          
  Console.Read();

    }

拆箱指令不包括将数据复制回栈的动作,在C#中只有将值类型作为引用类型的一个字段访问才能直接访问堆上的值类型。接口是引用类型,所以通过接口访问已装箱的值可避免拆箱和复制

当调用值类型的接口方法,实例必须是一个变量,方法可能改变这个值。拆箱会生成一个托管地址,运行时有一个存储位置和变量。结果运行时只传递托管地址而不进行拆箱操作。


避免拆箱:

            int number;
            object thing;
            number = 42;
            thing = number;
            string text = ((IFormattable)thing).ToString("X",null);
            Console.WriteLine(text);

接口属于引用类型,所以调用某成员时不需要拆箱。除此之外,调用struct的tostring()方法(重写了object的tostring()方法)也不需要拆箱。编译时从struct的tostring()调用值类型都是密封的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值