本帖最后由 seaxiao 于 2010-08-08 01:50:02 编辑

解决方案 »

  1.   

    foreach就是foreach,不要for...foreach时,被枚举集合的Length和Count是不能改变的,也就是说,进入foreach后,被for的集合不可以做添加或删除动作,否则出错!
      

  2.   

    楼上的没明白我的意思,请看红色字体。方法二的employees好象只能add成功最后一个emp.
      

  3.   

    我只是想问一下,由于变量的声明位置不同。为什么方法二 不能把每个emp都被add,而方法一却可以。
      

  4.   

    方法二是猴子掰玉米,掰一个丢一个...去看看MSDN,弄明白什么叫引用类型、引用类型的特征...
      

  5.   

    你这个问题就象问,都走入同一个社会,为什么张三能进监狱,李四就没监狱一样谁知道,某人在决定进不进监狱前发生了什么事情(假定你在for中又new 出来一个新的employees)
      

  6.   

    我知道方法二有问题,有点搞不明白?emp不是存在栈当中的吗?是不是for循环中每次new一下,emp都会分配过?
      

  7.   

    struct也许是栈里分配的,也许不是,class肯都是去堆里分配的,GC有一个原则,当前栈里存在的引用,肯定不会在栈被退出前回收(这点可以通过在.net中创建的COM对象的行为证明)在分配与析构上你的这个问题我没遇到过,也想不到会出现什么问题在栈上的行为这与
    int** pp=malloc(32);
    int * p;
    for(int i=0;i<8;i++)
    {
    p= malloc(4);
    pp[i]=p;
    }是一样的
      

  8.   

    方法一emp是在循环内分配的,是不是每次循环都在栈中从新为emp分配空间?,每个emp引用不同的对象,所以add方法加入了多个对象。
    方法二只在循环外为emp分配一次空间,它虽然每次循环引用不同的对象,引用的对象变了,但本身始终不变,只能引用一个对象,所以add方法每次都把上次的对象替换掉了,最终只加入了一个对象。
    不知道理解的对不对。
      

  9.   

    struct也许是栈里分配的,也许不是,class肯都是去堆里分配的,GC有一个原则,当前栈里存在的引用,肯定不会在栈被退出前回收(这点可以通过在.net中创建的COM对象的行为证明)struct类似于CString,但.Net没有提供释放它的方法,CString的复制行为(通过重载=,拷贝构造函数),保证它在生命期内永远有效,struct几乎与它相同,但它的地址,会随着调用对象的不同而改变.class在它的最后一个引用离栈前,永远存活,.Net1.0时好象不是,堆里的两个对象互相引用也使GC不会对它进行回收,这点通过我对析构函数的调用证明过,2.0以后,堆里的引用不会引响对它的回收,只要它和引用它的引用,或引用它的引用的引用的引用(没限制)没有离栈,它就一直存活,显式的调用GC也不回收,所以你的代码不存在回收的可能.有的COM对象,是在GC回收后,才会完全结束自己的进程,正应为它的最后一个引用没离栈,所以进程只能等待GC在某个想发作的时间发作时,才回结束,这也是导致某些SB去用Kill Procress这种粗暴的方法去结束因为调用COM对象产生Excel进程的原因for和foreach块肯定是在一个新栈上进行的,但对你的代码不会影响.
      

  10.   

    方法一emp是在循环内分配的,是不是每次循环都在栈中从新为emp分配空间?,每个emp引用不同的对象,所以add方法加入了多个对象。每次都在堆中为新的emp分配空间,栈中的emp不过是一个堆中emp的地址,以现在的环境,也就是一个Int32,add不过是在一个Int32[]中添加了一个Int32方法二只在循环外为emp分配一次空间,它虽然每次循环引用不同的对象,引用的对象变了,但本身始终不变,只能引用一个对象,所以add方法每次都把上次的对象替换掉了,最终只加入了一个对象。
    不知道理解的对不对。还是每次都在堆中为新的emp分配空间,for栈中的emp还是不断指向堆中新创建的emp的地址,add还是在一个Int32[]中添加了一个Int32,每次add时,emp所指向堆中的地址都是不同的所以,你代码出错,100%是你不透露代码产生的原因
      

  11.   

    Employee显然是个class,引用类型对象是包括在栈中的引用和在托管堆中的对象实例的一个整体...你在循环中每次new时只是创建了一个新对象实例,但引用只有一个,引用地址再怎么变都只有一个对象...而方法一每次循环都声明一个新对象...这就是原因,所以叫猴子掰玉米...
      

  12.   


    我感觉这两种方式应该都是正确的,并且这两种方式占用的堆空间应该相当,相比之下在大部分情况下第二种占用的栈空间可能更少。分析原因如下:
        第一种方法:再循环体内,每次每次执行在线程堆栈中分配一个保存Employee对象引用的变量和在托管堆中分配一个Employee对象,接着将托管堆中对象的引用存放在employees中,知道该方法完成。所以所有Employee对象将得以保存。但此时线程堆栈中应该有了若干个保存Employee对象引用的变量。
        而第二种方案,在循环体外部定义了保存Employee对象引用的变量,使得该方法内部仅有一个该线程堆栈变量。在循环体内部,每次在托管堆中定义一个Employee对象,并将其引用存于所定义的变量引用中(注意每次返回的变量引用是不相同的),最后将引用保存在employees抽象数据结构中。这里要说明的是,不管在循环执行到什么时候,先前生成的对象并不会被回收,这有GC的特性决定的,因为先前声明的变量可通过应用程序的跟连接到,是可达对象图中的一部分。
       两种方式应该都是正确的,并且这两种方式占用的堆空间应该相当,相比之下在大部分情况下第二种占用的栈空间可能更少。第二中方法我得到了验证,不会出现楼主所说的方法二的employees好象只能add成功最后一个emp问题。
      

  13.   


    emp是引用类型,绝对不会在栈里分配,应该在托管堆中分配内存地址。
    而且只能有一个该类的实例。
      

  14.   

    怎么都不去亲自试验一下呢?结论肯定是:
    无论哪个方法,都会把for块中new出来的Employee加入到List中谁要是能写出让List不断的Add,只加入了最后一次new出来的Employee,那可就真是神人了
      

  15.   

    第一种方法,每循环一次,都定义一次emp,并且每次都会为这个变量分配一个地址,N次循环以后,实际上计算机已经做过N次这样的分配操作,只不前N-1次emp已经被GC回收了。简单地说就是可以生成N个emp实例,所以每次都能加进去。第二种方法,计算机只定义了一次emp,以后的每一次new,都没产生新实例,从头到尾只产生过一个实例,就是你第一次new emp对象的时候,那么不管怎么加,都只能加进去最后一个。引用类型除了能看见的属性,方法,字段等等以外,还包含了一个地址,一个方法表指针,还有一个同步控制索引。这些都是c#编译器加上去的,在IL里面可以看见。所以不管怎么new,这个引用的地址没变,只不过是把前面的N-1次new都刷新了一下而已。纯属个人见解。
      

  16.   


    你说错了,,看来你2颗星白拿了,,,你还不明白什么叫 引用类型么?emp   按照LZ说的分析  emp 是一个引用类型 他存放的是 地址 而不是值
    你new 100次  也只是说那个地址里的值变了  地址没变而你每次list.add  加的都是地址  而不是值  所以值就是最后一次加的
    而同一地址被加了无数次好比你家就是  emp  就是你家的地址,,你买了多少菜回去  都是放在你家
    因为他定义的emp  在for 外面 所以自始至终没有new 一个真正的地址出来
    而是不断的new 新的值 往旧地址里放
      

  17.   

    还是先搞明白  string  和 int 的区别吧,,,
    如果引用类型  值类型 搞不明白,,那非常遗憾,,你的代码真的可能会乱的一塌糊涂
      

  18.   

    相同点:
    方法一和方法二的employeesList结果应该是一样的。
    不同点:
    1、第一个方法的emp 在循坏外不可访问,而第二个方法的emp在循环结束后保存最后一个employees的引用。
    2、第一个方法每次声明一个employees类型的指针,该指针指向了一个新的employees对象。
       第二个方法只声明一个employees类型的指针,每次循环修改该指针的值指向了一个新的employees对象。
      

  19.   


    无论是值类型还是引用类型,局部变量的地址都是不会改变的,但你扔到集合中的不是变量的地址,而是变量的地址中所存放的值,对于Int类型,变量的地址存放值的是变量的值,对于class变量的地址存放的是class在堆中的地址
      

  20.   

    代码说话,自己拿去试试
        public class Node
        {
            int _id;
            int _parentId;
            IList<Node> _li = null;
            public Node(int id, int parentId)
            {
                _li = new List<Node>();
                _id = id;
                _parentId = parentId;
            }
            public int Id { get { return _id; } }
            public int ParentId { get { return _parentId; } }
            public IList<Node> Children { get { return _li; } set { _li = value; } }
            public void AddNode(Node _n)
            {
                if (null != _n)
                    _li.Add(_n);
            }
        } IList<Node> _l = new List<Node>();
                for (var i = 0; i < 10; i++)
                {
                    Node _n = new Node(i, i + 1);
                    _l.Add(_n);
                }
                var m = 0;
                foreach (var _n in _l)
                {
                    m++;
                    Console.WriteLine(m.ToString() + ":" + _n.Id.ToString());
                }            Console.WriteLine("======================");
                IList<Node> _ll = new List<Node>();
                Node _p;
                for (var i = 0; i < 10; i++)
                {
                    _p = new Node(i, i + 1);
                    _ll.Add(_p);
                }
                var n = 0;
                foreach (var _n in _l)
                {
                    n++;
                    Console.WriteLine(n.ToString() + ":" + _n.Id.ToString());
                }            Console.Read();
      

  21.   

    上面的测试错了   IList<Node> _l = new List<Node>();
                for (var i = 0; i < 10; i++)
                {
                    Node _n = new Node(i, i + 1);
                    _l.Add(_n);
                }
                var m = 0;
                foreach (var _n in _l)
                {
                    m++;
                    Console.WriteLine(m.ToString() + ":" + _n.Id.ToString());
                }            Console.WriteLine("======================");
                IList<Node> _ll = new List<Node>();
                Node _p;
                for (var i = 0; i < 10; i++)
                {
                    _p = new Node(i, i + 1);
                    _ll.Add(_p);
                }
                var n = 0;
                foreach (var _n in _ll)
                {
                    n++;
                    Console.WriteLine(n.ToString() + ":" + _n.Id.ToString());
                }            Console.Read();
      

  22.   

    lz说有问题,可是我测试了一下没问题啊class Program
        {
            static void Main(string[] args)
            {
                List<Dog> dogs = new List<Dog>();
                Dog dog;
                for(int i=0;i<10;++i)
                {
                    dog = new Dog("dog "+i.ToString());
                    dogs.Add(dog);
                }
                foreach (Dog d in dogs)
                {
                    Console.WriteLine(d.name);
                }
            }
        }    class Dog
        {
            public Dog()
            {
            }
            public Dog(string name)
            {
                this.name = name;
            }
            public string name;
        }
      

  23.   

    就这问题还扯到装箱、堆栈了
    lz的代码不会出现lz所说的问题,lz还是仔细检查一下代码是不是贴错了
      

  24.   

    LZ的问题应该是对象调用不同,方法一是每次都创建一个新的对象,而方法二即每次都把原来的对象重新创建,所以到最后只能得到最后一个值,LZ可以调试时断点看下过程,希望能帮到你!
      

  25.   

    樓主的程式是不是貼錯了。兩段程式的功能都是相同的。如果說有差別的話,我認為第二種效率會更高一些,因為GC不用作n-1次無用功。
      

  26.   

    不知道楼主真的谢过这两段代码没有。我是真的自己写了一遍。两段代码的结果是完全一样的
    如果非要找出什么的话
    List<Employee> employees = new List<Employee>();
    Employee emp = new Employee();
    for(...)
    {employees.add(emp);
    }
    只有这样。employees中的emp才是会指向同一个。
    如果不是这样的话,那就是楼主的中间代码有问题了
      

  27.   

    public class Employee
        {
            private string name;        public string Name
            {
                get { return name; }
                set { name = value; }
            }
        }    class Program
        {
            static void Main(string[] args)
            {
                List<Employee> emp = new List<Employee>();            Employee employee;            for (int i = 0; i < 10; i++) 
                {
                    employee = new Employee();
                    employee.Name = i.ToString();                emp.Add(employee);
                }            foreach (Employee temp in emp)
                {
                    Console.WriteLine(temp.Name);
                }                Console.ReadLine();        }
        }没有发现你说的问题。