使用接口更改已装箱的值类型中的字段

先看下面一段代码

namespace 使用接口更改已装箱值类型的字段
{
    //point是一个值类型

    internal struct Point
    {
        private Int32 m_x, m_y;
        public Point(Int32 x, Int32 y)
        {
            m_x = x;
            m_y = y;
        }
        public void Change(int x, int y)
        {
            m_x = x;
            m_y = y;
        }
        public override string ToString()
        {
            return string.Format("({0},{1})", m_x, m_y);
            //fromat返回指定字符串中一个或多个格式项替换为指定对象的字符串格式
        }
        class Program
    {

        }
        static void Main(string[] args)
        {

        Point p = new Point(1, 1);
        Console.WriteLine(p);//显示(1,1)
        p.Change(2, 2);
        Console.WriteLine(p);//显示(2,2)
        object o = p;
        Console.WriteLine(o);//显示(2,2)
        ((Point)o).Change(3, 3);
        Console.WriteLine(o);//显示(2,2)
        Console.ReadKey();

        }
    }
}

  Main在栈上创建一个Point值类型对象并赋值(1,1),第一次调用writeline之前对p进行装箱,writeline会在已装箱的Point上调用ToString,像预期中结果为(1,1)

p调用Change方法将数值改为2,第二次调用writeline时再次对p进行装箱,像预期结果为(2,2)

现在p要进行第三次装箱,o将引用已装箱的Point对象,第三次调用writeline会显示(2,2)

  最后希望调用Change来更改已装箱的Point对象中的字段,但是Object o 对Change方法并不知情所以要先将o转型为Point。将o转型为Point要先将o拆箱,并将已装箱中的字段

复制到线程栈上一个临时的Point中。这个临时的Point的m_x,m_y会变成3,3,但是已装箱的Point不受这个Change调用影响,所以第四次显示(2,2)

用接口来更改已装箱值类型的字段

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 使用接口更改已装箱值类型的字段
{

    //接口定义一个Change方法
    internal interface IChageBoxedPoint
    {
        void Change(int x, int y);
    }
    //point是一个值类型

    internal struct Point: IChageBoxedPoint
    {
        private Int32 m_x, m_y;
        public Point(Int32 x, Int32 y)
        {
            m_x = x;
            m_y = y;
        }
        public void Change(int x, int y)
        {
            m_x = x;
            m_y = y;
        }
        public override string ToString()
        {
            return string.Format("({0},{1})", m_x, m_y);
            //fromat返回指定字符串中一个或多个格式项替换为指定对象的字符串格式
        }
        class Program
    {

        }
        static void Main(string[] args)
        {
            Point p = new Point(1, 1);
            Console.WriteLine(p);//显示(1,1)
            p.Change(2, 2);
            Console.WriteLine(p);//显示(2,2)
            object o = p;
            Console.WriteLine(o);//显示(2,2)
            ((Point)o).Change(3, 3);
            Console.WriteLine(o);//显示(2,2)
            //对p进行装箱,更改已装箱的对象,然后丢弃它;
            ((IChageBoxedPoint)p).Change(4, 4);
            Console.WriteLine(p);//显示(2,2)     //更改已装箱的对象病显示他
            ((IChageBoxedPoint)o).Change(5,5);
            Console.WriteLine(o);//显示(5,5)
        }
    }
}

  

这段代码与上边的主要区别是change方法由

IChageBoxedPoint接口定义,Point类型实现了这个接口。
  //对p进行装箱,更改已装箱的对象,然后丢弃它;
            ((IChageBoxedPoint)p).Change(4, 4);
            Console.WriteLine(p);//显示(2,2)
这里未装箱的Point p 转型为IChangeBoxedPoint,这个转型造成对p的值进行装箱,然后已装箱的值上调用Change,这确实让m_x,m_y变成了4,4,但是,在Change返回之后,已装箱的对象立即装备好进行垃圾回收,所以显示(2,2)最后的例子中,o引用已装箱Point要转型为一个IChageBoxedPoint。这里不需要进行装箱,因为o已经是一个装箱的Point。然后调用Change,他能正确修改已装箱的Point的m_x,m_y字段。接口方法允许更改一个已装箱的Point对象中的字段。
时间: 2024-10-25 11:15:50

使用接口更改已装箱的值类型中的字段的相关文章

Lambda Func<T,TKey> 取值类型时得到字段名的一种方法

@Html.InputTextFor(s => s.name) 取得s.name中的name dynamic exp = expression.Body.GetType().GetProperty("Member").GetValue(expression.Body, null); var strName = (string)exp.Name; strName为name

值类型的装箱和拆箱

在CLR中为了将一个值类型转换成一个引用类型,要使用一个名为装箱的机制. 下面总结了对值类型的一个实例进行装箱操作时内部发生的事: 1)在托管堆中分配好内存.分配的内存量是值类型的各个字段需要的内存量加上托管堆上的所有对象都有的两个额外成员(类型对象指针和同步块索引)需要的内存量. 2)值类型的字段复制到新的分配的堆内存. 3)返回对象的地址.现在,这个地址是对一个对象的引用,值类型现在是一个引用类型. 拆箱不是直接将装箱过程倒过来.拆箱的代价比装箱低得多.拆箱其实就是一个获取一个指针的过程,该

值类型的装箱与拆箱浅析

值类型的装箱与拆箱浅析 2012-02-23 15:47 by 秋梧, ... 阅读, ... 评论, 收藏, 编辑 阅读目录 前言 值类型的装箱 值类型的拆箱 装箱和拆箱实例 结束语 前言 在.Net 中值类型向引用类型的转换以及从引用类型到值类型的转换是需要装箱(boxing)和拆箱(unboxing)的,这是因为值类型是比引用类型更轻型的一种类型,因为他们不想对象那样在托管队中分配,不会被GC收集,而且不需要通过指针来引用.但是在许多情况下都需要获取对值类型的一个实例的引用.对于在值类型与

第五章 基元类型、引用类型 和 值类型

1. 概述 本章讨论MS.NET Framework开发人员经常接触到的各种类型. 2. 名词解释 ① 基元类型:编译器直接支持的数据类型. ② 装箱:将一个值类型转换成一个引用类型. ③ 拆箱:获取已装箱的对象中的各个字段的地址. 3. 主要内容 3.1 编程语言的基元类型 作者建议开发人员开发中使用FCL类型名称,不要使用简化的基元类型名称.原因如下: ① 简化名称的映射容易混淆. ② 不同的编程语言,规则不一. ③ 影响代码的阅读. ④ 时间长了容易忘掉多语言环境的支持. checked

第5章 基元类型、引用类型和值类型

5.1编程语言的基元类型 编译器(Compiler)直接支持的数据类型称为基元类型(primitive type). 我希望编译器根本不要提供基元类型名称,强制开发人员使用FCL(Framework类库)类型名称: 许多开发人员都困惑于到底应该使用string还是String.由于C#的string直接映射到System.String,所以两者是没有区别的.int始终映射到System.Int32,所以不管在什么操作系统上运行,代表的都是32位整数. 5.2引用类型和值类型 虽然FCL中大多数类

c#中的引用类型和值类型

一,c#中的值类型和引用类型 众所周知在c#中有两种基本类型,它们分别是值类型和引用类型:而每种类型都可以细分为如下类型: 什么是值类型和引用类型 什么是值类型: 进一步研究文档,你会发现所有的结构都是抽象类型System.ValueType的直接派生类,而System.ValueType本身又是直接从System.Object派生的.根据定义所知,所有的值类型都必须从System.ValueType派生,所有的枚举都从System.Enum抽象类派生,而后者又从System.ValueType

C#中的基元类型、值类型和引用类型

C# 中的基元类型.值类型和引用类型 1. 基元类型(Primitive Type) 编译器直接支持的类型称为基元类型.基元类型可以直接映射到 FCL 中存在的类型.例如,int a = 10 中的 int 就是基元类型,其对应着 FCL 中的 System.Int32,上面的代码你完全可以写作System.Int32 a = 10,编译器将生成完全形同的 IL,也可以理解为 C# 编译器为源代码文件中添加了 using int = System.Int32. 1.1 基元类型的算术运算的溢出检

C#本质论6.0第八章:值类型

值类型与引用类型: 值类型: 值类型的变量直接包含值,变量引用的位置就是值在内存中实际存储的位置.因此,将一个原始变量的值赋给另一个变量,会在新变量的位置创建原始变量的值的一个内存副本.两个变量不可能引用同一个内存位置.同样的,在方法内部对参数值进行任何修改都不会影响调用者中的原始值.由于值类型需要有一个内存副本,所以定义时通常不要让它消耗太多内存. 值类型的值一般只是短时间存在,很多情况下,这样的值只是作为表达式的一部分,或用于激活方法,在这些情况下,值类型的变量和临时值经常是存储在成为栈的临

[CLR via C#]值类型的装箱和拆箱

我们先来看一个示例代码: namespace ConsoleApplication1 { class Program { static void Main(string[] args) { ArrayList a = new ArrayList(); Point p; for (int i = 0; i < 10; i++) { p.x = p.y = i; a.Add(p); } Console.ReadKey(); } } struct Point { public Int32 x, y;