本帖最后由 clover8 于 2010-06-17 15:30:14 编辑

解决方案 »

  1.   

    items[1]是值类型,就不能在用 . 操作符了结构怎么就不能按引用传递,是c#的设计
      

  2.   

    结构和类的区别之一就是结构是值类型,类是引用类型。
    结构是在栈上分配空间的,类是在栈上分配一个变量指针,使用new后在堆上分配存储工具,所以没有被new的类是null,而结构不会是null
      

  3.   

    请问3楼的说法,是不是非C#独有的情况,对于C++,Java也是一样的?刚查到:“Java中,简单类型是按值传递的”
    “Java 方法的参数是按什么传递的问题,其答案就只能是:即是按值传递也是按引用传递,只是参照物不同,结果也就不同。”
    “Java 中,改变参数的值有两种情况,第一种,使用赋值号“=”直接进行赋值使其改变;第二种,对于某些对象的引用,通过一定途径对其成员数据进行改变。对于第一种情况,其改变不会影响到方法该方法以外的数据,或者直接说源数据。而第二种方法,则相反,会影响到源数据——因为引用指示的对象没有变,对其成员数据进行改变则实质上是改变的该对象。”我可否理解成:
    1。类的实例在使用的时候,都是按引用传值?C++, C#, Java都是这样。2。而另外一方面,函数参数传值的时候,C#和Java一样,即是按值传递也是按引用传递,只是参照物不同,结果也就不同。而C++因为还存在指针,所以执行的是另外一套规则?谢谢了。
      

  4.   

    所有的引用类型,都是在heap中分配内存的,对引用类型的操作,例如赋值等,都是对引用类型的“指针”进行操作的!
    例如ClassA a=new ClassA();
    ClassA otherA=a;
    //这里a和otherA都是引用类型,他们引用的都是新建的ClassA对象的地址。
    //本质上说,a和otherA的内存空间中,存放的不是创建的对象的内容,而是指向对象内容存放空间的首地址!
    而值类型是在stack中分配内存的。
    //这里使用的是结构,故不能直接用 items[1].DisplayText = "金星";,如果 Item 是类,则可以直接用。
    //为什么呢?因为结构是按值传递的。结构类型是值类型,这是C#编译器的设计,所以不能像类一样用.号引用成员!
      

  5.   

    请问下5楼,因为Java和C#实在太像了,那么Java编译器也是这么处理的吧?..
      

  6.   

    结构类型是值类型,这是C#编译器的设计,所以不能像类一样用.号引用成员!为什么结构不能用.引用成员,我们给结构体复制的时候不都是.成员名 = “” 吗?eg.public struct Item
    {
      public int Id;
      public string DisplayText;
    }Item item1 ;
    item1.Id = 0;   // 这个地方不是通过. 成员  来赋值的吗
    item1.DisplayText = "水星";
      

  7.   

    请问下5楼,因为Java和C#实在太像了,那么Java编译器也是这么处理的吧?..java有结构体吗?
      

  8.   

    Java在这点上比C#差一些了。Java的Primary Type是值类型的,例如int, long, boolean.
    Java 1.5的enum类型是值类型的,
    其他都是引用类型的。C#的struct可以定义值类型,class定义引用类型,enum定义值类型。就这样~
      

  9.   


    Java没有结构体,很耗费JVM的heap。
      

  10.   

    struct是值类型,但是值类型和引用类型都可以按引用传递。
    用引用传递值类型可以提高性能
      

  11.   


    public struct Item
        {
            public int Id;
            public string DisplayText;
        }
        class Program
        {
            static void Main(string[] args)
            {
                List<Item> items = new List<Item>();            //添加
                Item item1 = new Item();
                item1.Id = 0;
                item1.DisplayText = "水星";
                items.Add(item1);            //添加
                Item item2 = new Item();
                item2.Id = 1;
                item2.DisplayText = "地球";
                items.Add(item2);            Item item = items[1];
                item.DisplayText = "jinxing";
            }
        }这段代码没问题啊,楼主
      

  12.   

    值传递应该是先建立一个copy,然后再传过去吧
    不过copy完了后,这个临时的拷贝应该就被销毁了吧
      

  13.   


    虽然代码没有问题,那是因为你没有测试到“点子”上。如果你打印items[1]的内容,仍然是“地球”而不是“金星”!
      

  14.   

    结构怎么就不能按引用传递?这个是谁说的? 纯粹的胡说八道   使用ref参数不就是按照引用来传递吗
      

  15.   

    或许个别从c++(而且也不是做应用系统,而是花一年时间才死抠一小段底层代码,整天谈论“效率”的人)刚刚转入c#是可能习惯使用struct。我对c#程序员的建议是:永远不要去主动去想要使用struct。
      

  16.   

    sp1234所说的貌似以前看到过类似的建议http://msdn.microsoft.com/zh-cn/library/ah19swz4(VS.80).aspx
    结构还可以包含构造函数、常量、字段、方法、属性、索引器、运算符、事件和嵌套类型,但如果同时需要上述几种成员,则应当考虑改为使用类作为类型。
    http://msdn.microsoft.com/zh-cn/library/saxz13w4(v=VS.80).aspx
    结构与类共享几乎所有相同的语法,但结构比类受到的限制更多: •在结构声明中,除非字段被声明为 const 或 static,否则无法初始化。•结构不能声明默认构造函数(没有参数的构造函数)或析构函数。结构的副本由编译器自动创建和销毁,因此不需要使用默认构造函数和析构函数。实际上,编译器通过为所有字段赋予默认值(参见默认值表)来实现默认构造函数。结构不能从类或其他结构继承。结构是值类型 -- 如果从结构创建一个对象并将该对象赋给某个变量,变量则包含结构的全部值。复制包含结构的变量时,将复制所有数据,对新副本所做的任何修改都不会改变旧副本的数据。由于结构不使用引用,因此结构没有标识 -- 具有相同数据的两个值类型实例是无法区分的。C# 中的所有值类型本质上都继承自 ValueType,后者继承自 Object。结构设计请注意这个例子,MSDN的这个例子和楼主要的完全吻合。
    如何:了解向方法传递结构和向方法传递类引用之间的区别(C# 编程指南)
      

  17.   

    为什么说吻合呢,我们看看List<T>的get方法[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
    public T get_Item(int index)
    {
        if (index >= this._size)
        {
            ThrowHelper.ThrowArgumentOutOfRangeException();
        }
        return this._items[index];
    }
    是什么意思?
    return this._items[index];
    this._items[index]已经是一个副本了。所以你通过List[i]访问的,就是副本,无法修改。
      

  18.   


    首先要明白什么叫做按值、按引用传递?这里去重复c语言规则就会出笑话了。当你在调用方法的参数上,假设传递的是对象,不写ref就是按值传递对象吗?写ref就是按引用传递对象吗?如果你这样理解就完全把c的概念张冠李戴到c#上了。这样,也就无法进一步理解值类型的数据的传递。
      

  19.   

    可能还没明白么?
    再说明白一点this._items[index],这个是的的确确你添加进去的那个结构体,但结构体是传值的,在函数调用 void Foo(StructValue o)
    这里,你的o是传递的值,那么换一种写法
    StructValue Foo()
    {
        StructValue f;
        return f;//你认为这里返回的是f还是f的副本呢?想明白这个,结合List索引器的get代码,应该明白原因了,不要纠结了,换用类吧。
    }
      

  20.   

    今天看楼主帖子,督促自己看了msdn,恩。吧这个List<T>无法修改item的问题终于搞清楚了。happy
      

  21.   

    在调用一个方法时,不论你写ref或者不写,传递的都是一个引用。而对struct,都是复制一个副本。不过我倒是不关心struct,我倒是关心对象作为参数。“根据情况来按值或者引用传递”的误解就是对ref的误解。不论写不写它,对于对象做参数都是传递引用。或者你可以说,对象的引用被作为对象而传递了。
      

  22.   

    struct的问题就是一不小心,我们就只是修改副本,还不知道。就好象 #14 楼一样。这样所花费精力写的代码不少,还容易产生很多bug难以发现,因此最好不要使用struct。
      

  23.   


    非常贴切,但未必能理解。我举个例子描述一下sp1234大神的意思。
    public class A
    {
        public int i = 0;
    }A obj = new A();
    public void Foo(obj);public void Foo(A a)
    {
        a.i = 5;//你可以修改a的i属性,因为a是传递的引用。但写不写ref可不同哦。
        a = new A();//你可以给a重新赋值,但是a是传进来参数的副本,a的修改不过是形参,obj.i已然是5,不是0
    }A obj = new A();
    public void Foo(ref obj);public void Foo(ref A b)
    {
        b.i = 6;//b作为引用,修改i的值为6
        b = new A();//你可以修改b的值,离开方法后,参数就变了,obj.i就是0了。
    }
      

  24.   

    ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
    按引用传递值类型(如本主题前面所示)是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。下面的示例显示出当引用类型作为 ref 参数传递时,可以更改对象本身。
      

  25.   

    处于好奇好玩,写个例子给大家看看。以证明我上面的分析。private static void TestChangeStructList()
    {
        //定义一个泛型List
        List<AA> datas = new List<AA>();
        //添加2个元素,value分别为1,2
        datas.Add(new AA(1));
        datas.Add(new AA(2));
        //打印出当前元素
        Console.WriteLine("原始List:");
        datas.ForEach(o => Console.WriteLine(o.value.ToString()));
        //使用List的索引器赋值
        datas.ForEach(o => o.value++);
        //打印出当前元素
        Console.WriteLine("使用List的索引器赋值");
        datas.ForEach(o => Console.WriteLine(o.value.ToString()));
        //反射List内部的值类型数组赋值
        AA[] items = (AA[])((FieldInfo)(datas.GetType().GetMember("_items", BindingFlags.NonPublic | BindingFlags.Instance)[0])).GetValue(datas);
        items[0].value++;
        items[1].value++;
        //打印出当前元素
        Console.WriteLine("反射List内部的值类型数组赋值");
        datas.ForEach(o => Console.WriteLine(o.value.ToString()));
    }结果原始List:
    1
    2
    使用List的索引器赋值
    1
    2
    反射List内部的值类型数组赋值
    2
    3还没看懂的,最后再讲一次。
    List<T>[i]
    这是叫做索引器的,索引器是一种属性,属性就是在调用方法,而值类型无法返回一个引用,返回的是值,所以索引器返回的,是你添加进去变量的副本。而因为值类型无法传递引用,所以添加实际也是使用副本的方式添加的。所以对于值类型的List<T>,索引器的结果,可以访问,可以修改,但无法直接存回去,如何保存?可以重新的赋值,例如
    List<Point> points = new List<Point>();
    points.Add(new Point());//0,0
    修改呢,就整个重新复制
    points[0] = new Point(1,1);
    你不能修改一项points[0].X = 1;
    这样不可以的。希望这样说,各位不明白的能明白。明白的更明白。
      

  26.   

    忘记贴了,AA定义public struct AA
    {
        public int value;
        public AA(int v)
        {
            value = v;
        }
    }
      

  27.   

    结构是值类型
    类是引用类型但是结构也可以用引用方式传递 
    用关键字 ref