class Test
    {
        interface IAddOne
        {
            int AddOne();
        }
        struct FixPoint : IAddOne
        {
            int _x;
            public FixPoint(int x)
            {
                _x = x;
            }
            public int AddOne()
            {
                ++_x;
                return _x;
            }
        }
        static void Main()
        {
            ArrayList pointList = new ArrayList(1);
            FixPoint f = new FixPoint(0);
            pointList.Add(f);
         
            Console.Write(f.AddOne());
            Console.Write(f.AddOne());
            Console.Write(f.AddOne());
            
            Console.WriteLine();
           // Console.WriteLine(pointList[0]); // 输出结果为ConsoleApplication1.Test+FixPoint            Console.Write(((IAddOne)pointList[0]).AddOne());            FixPoint p = (FixPoint)pointList[0];
            Console.Write(p.AddOne());
            Console.Read();
        }
    }
前面经过3次调用,_x的值变为3,保留在栈中,这道题的结果为啥不是12345,或者12314?
难道后两次输出不会关联到前3次?为啥最后一次输出会关联到第四次输出?(第四次输出1,第5次输出2)

解决方案 »

  1.   

    明显觉得脑袋现在不好用,看了半天才从坑里爬出来。
     pointList.Add(f);
    问题的关键在这句。弄明白这句做什么事,你的疑问就消除了。如果没想清楚,从标题找答案,也可以适当修改程序,便于加深理解。FixPoint p = (FixPoint)pointList[0];
    Console.Write(p.AddOne());=》FixPoint p = (FixPoint)pointList[0];
    Object obj = pointList[0];
    Console.Write(p.AddOne());
    Console.Write(((FixPoint)obj).AddOne());
      

  2.   

    看不懂,pointList.Add(f);这句话后_x的值确实自加了1
      

  3.   

    那就先弄明白这几句FixPoint p = (FixPoint)pointList[0];
    Object obj = pointList[0];
    Console.Write(p.AddOne());
    Console.Write(((FixPoint)obj).AddOne());
    接口保存在堆 是错误的断言。
      

  4.   

    interface a
    {}
    struct b:a
    {}
    a a1 = new b
    a1保存在啥地方呢?
      

  5.   

    对着你的代码,运行,盯了10分钟,脑里面一片空白,特别是下面代码最后的输出结果:
     Console.Write(f.AddOne());
                Console.Write(f.AddOne());
                Console.Write(f.AddOne());            Console.WriteLine();
                Console.WriteLine(pointList[0]);            Console.Write(((IAddOne)pointList[0]).AddOne());//值类型,保存在栈上             //FixPoint p = (FixPoint)pointList[0];//引用类型,保存在受管制的堆上
                //Console.Write(p.AddOne());            FixPoint p = (FixPoint)pointList[0];
                Object obj = pointList[0];
                Console.Write(p.AddOne());
                Console.Write(p.AddOne());
                Console.WriteLine(p.AddOne());
                Console.Write(((FixPoint)obj).AddOne());            Console.Read();
      

  6.   

    上面代码的结果:
     123
    ConsoleApplication1.Test+FixPoint
    1234
    2
      

  7.   

     ArrayList pointList = new ArrayList(1);
                FixPoint f = new FixPoint(0);
                pointList.Add(f);//装箱且发生复制 Pointlist[0] 和 f已经没有关系了
             
                Console.Write(f.AddOne());
                Console.Write(f.AddOne());
                Console.Write(f.AddOne());
                
                Console.WriteLine();
                         Console.Write(((IAddOne)pointList[0]).AddOne());//这里通过interface直接对pointlist[0]操作            FixPoint p = (FixPoint)pointList[0];//解装箱且发生复制 p和pointlist[0]没有关系了
                Console.Write(p.AddOne()); 
                Console.Read();
      

  8.   

    FixPoint p = (FixPoint)pointList[0];//解装箱且发生复制 p和pointlist[0]没有关系了
    ------------------------------------------------------
    p和pointlist[0]没有关系了 不是的
      

  9.   

     Console.Write(((IAddOne)pointList[0]).AddOne());//这里通过interface直接对pointlist[0]操作  FixPoint p = (FixPoint)pointList[0];//解装箱且发生复制 p和pointlist[0]没有关系了
    这里两处发生的都是拆箱操作吧?貌似看你这么解释,好像跟哪些局部变量,结构,接口存在堆和栈完全没关系了
      

  10.   

    恩貌似有关系,我调试下面代码,运行到obj后,obj里面的x变成1了
      FixPoint p = (FixPoint)pointList[0];
      Object obj = pointList[0];
      Console.Write(p.AddOne());
      

  11.   

    额  看来还是有必要说明一下啊12312这个问题的原因是因为值类型的一个特点,就是= 赋值赋值的时候,会创建=右侧的一个副本 给左侧。简单说就是不同实例。而 pointList.Add(f); 在内部就是一个 = 操作。((IAddOne)pointList[0]).AddOne(), (IAddOne)pointList[0] 这里是类型转换,但还是同一实例(FixPoint)pointList[0]; 也是一样,类型转换,同一实例。需要重点说明的就是 = 会产生副本、类型转换不会。  
      

  12.   

    装箱操作会复制值类型。
    复制出来新对象与原有的一点关系都没有了,
    在内存中会占用一个新的空间
    而引用类型 只是地址引用
    struct 是值类型 
    所以在pointList.Add(f); 时已经做了装箱 被复制 
    所有的对f 的操作 不会影响到 pointList 
    如果 把struct 改成 class 
    输出的内容 就会是12345 因为类是引用类型 只是引用了 对象的地址,
    并不是实际的值 ,所有的操作都会影响到原对象。
    我理解的!嘿,
      

  13.   

    接口是虚拟的,不能直接创造的
    interface a{}
    你不能 a a1 = new a()
    而且他能够被引用类型和值类型,实现所以不能所接口就是引用类型,就是值类型
    所谓的装箱
    就是从栈中把变量复制到堆中,反装箱就是相反的操作
    interface a = pointlist[] ,因为interface 的不确定性,所以不引起反装箱
    Farpoint p = pointlist[]则引起了反装箱
      

  14.   

    之前pointList[0]._x =0;((FixPoint)(pointList[0])).AddOne();
    之后  
    pointList[0]._X == ???
    改成
       ((FixPoint)(pointList[0])).AddOne();
    ((IAddOne)(pointList[0])).AddOne();
    之后呢??
    运行一下就清楚了
      

  15.   

    装箱拆箱只是进行类型转换,不会产生副本。
    ----------------------------------
    是我搞错了,装箱操作会产生副本的。hdt大叔是对的,“因为interface 的不确定性,所以不引起反装箱
    ” 只是这句我不赞同。有时间会把这个事详细说清楚。
      

  16.   

    我说的可能有些随意了,毕竟有些日子没有搞.net,一些术语记不清了,刚才查了一下msdn ,上面说把值类型转为object 或它实现的接口,就会发生装箱,反装箱也应该按差不多的规则。
      

  17.   

    我觉得这不是拆箱装箱的问题,而是值类型和引用类型的问题,如果把struct换成class的话就完全一目了然了,在ArrayList中add入一个值,是一个副本,就算拆箱装箱仍旧是针对改副本的处理PS:是有值类型保存盏上,引用类型保存堆上的说法,结构体属于值类型,类属于引用类型,而接口类似于纯虚类
      

  18.   

    这个我觉得最靠谱 
     Console.Write(((IAddOne)pointList[0]).AddOne());==》修改成    Console.Write(((FixPoint)pointList[0]).AddOne()); 4和5的输出就是11 
    这个是针对struct类型的 
    但是当struct改成clas时,结果就是12345 可见当为clss时都是引用同一个对象
    个人总结:strut为值类型 封箱和拆箱都是复制对象 而当为引用类型时 则都引用同一个对象。
      

  19.   

    其实这跟装箱拆箱接口什么的都没关系,你新建一个FixPoint f2 = f;然后f.AddOne()就看得出来,其实只有f自身会ADD,也就是说,结构体作为值类型你添加到LIST以后再对它自身操作并不会影响到LIST里面的值,因为它们不是同个引用
      

  20.   

    学习了,希望能和大家多交流,以后常来往
    http://hi.csdn.net/space.html
      

  21.   

    我来答一下:
    pointList.Add(f);
    这一行代码导致f被从栈中装箱后放到了托管堆上,堆上的对象是复制的_x是0的FixPoint;现在堆上的object类型和栈上的f没有关系了,所以调用f.AddOne()是不会影响堆上对象的_x的下面的代码是将堆上的object类型转换成IAddOne,这时候堆上_x在AddOne调用之前是0,调用后输出是1,IAddOne接口是引用类型,他调用后直接改变堆上的值
    Console.Write(((IAddOne)pointList[0]).AddOne());//下面一行代码需要将堆上的object(注意这时候他的_x字段是1)拆箱,然后复制到栈上,复制到栈上时他的_x是1
    FixPoint p = (FixPoint)pointList[0];
    //再次AddOne自然是在1的基础上加1
    Console.Write(p.AddOne());有关装箱和拆箱看下我的博客吧
    http://www.cnblogs.com/yukaizhao/archive/2011/10/18/csharp_box_unbox_1.html
      

  22.   

    我来答一下:
    pointList.Add(f);
    这一行代码导致f被从栈中装箱后放到了托管堆上,堆上的对象是复制的_x是0的FixPoint;现在堆上的object类型和栈上的f没有关系了,所以调用f.AddOne()是不会影响堆上对象的_x的下面的代码是将堆上的object类型转换成IAddOne,这时候堆上_x在AddOne调用之前是0,调用后输出是1,IAddOne接口是引用类型,他调用后直接改变应该是栈上的f的值
    Console.Write(((IAddOne)pointList[0]).AddOne());//下面一行代码需要将堆上的object(注意这时候他的_x字段是1)拆箱,然后复制到栈上,复制到栈上时他的_x是1
    FixPoint p = (FixPoint)pointList[0];
    //再次AddOne自然是在1的基础上加1
    Console.Write(p.AddOne());有关装箱和拆箱看下我的博客吧
    http://www.cnblogs.com/yukaizhao/archive/2011/10/18/csharp_box_unbox_1.html
      

  23.   

    Reference Types (C# Reference)
    Visual Studio 2010 Other Versions  Visual Studio 2008 Visual Studio 2005 Visual Studio .NET 2003 Variables of reference types, referred to as objects, store references to the actual data. This section introduces the following keywords used to declare reference types: classinterfacedelegateThis section also introduces the following built-in reference types: dynamicobjectstringhttp://msdn.microsoft.com/en-us/library/490f96s2.aspx
      

  24.   

    hdt  说的是对的,看看我的测试代码就知道了。using System;
    using System.IO;
    using System.Text;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;class Hello {
    static void Main() {            ArrayList pointList = new ArrayList(1);
                FixPoint f = new FixPoint(0); // 此处引起装箱, f 和 pointList[0] 虽数据相同,却已经不是同一个对象了。
    // f 指向的是 栈 中的对象,而 pointList[0] 却指向的是 堆中 被装箱的对象。
                pointList.Add(f);
             
                Console.Write(f.AddOne());
                Console.Write(f.AddOne());
                Console.Write(f.AddOne());
                
                Console.WriteLine();
                Console.WriteLine(pointList[0]); // 输出结果为FixPoint
    Console.WriteLine(((FixPoint)pointList[0])._x); //输出为 0             Console.WriteLine(((IAddOne)pointList[0]).AddOne());//输出为 1     强制转换为 接口 ,不会导致拆箱
    Console.WriteLine(((FixPoint)pointList[0]).AddOne());//输出为 2    强制转换为 stuuct ,会导致拆箱 ,修改的是复制到 栈 中的对象            FixPoint p = (FixPoint)pointList[0]; //拆箱发生复制 p和pointlist[0]没有关系了
                Console.WriteLine(p.AddOne()); //输出为 2

    Console.WriteLine(((FixPoint)pointList[0])._x); //输出为 1             Console.Read();
    } public static void wl(String format, params Object[] arg) {
    Console.WriteLine(format, arg);
    }
    }        interface IAddOne
            {
                int AddOne();
            }
            
    struct FixPoint : IAddOne
    //class FixPoint : IAddOne
            {
                public int _x;
                public FixPoint(int x)
                {
                    _x = x;
                }
                public int AddOne()
                {
                    ++_x;
                    return _x;
                }
            }