none
c#值类型和引用类型存储值的相关问题 RRS feed

  • 问题

  • 我知道值类型存储的是数据的实际值,引用类型存储的是值的引用。但这样的程序str1的值怎么没有改变呢?本人菜鸟。。
          int a = 1;
          string str = "ab";
          Console.WriteLine("a is {0},str is {1}", a, str);
          int b = a;
          a=2;
          string str1 = str;
          str = "abc";
          Console.WriteLine("b is {0},str1 is {1}", b, str1);
          Console.Read();
    
    2010年12月20日 23:04

答案

  • string   对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因,如果经常改变string的值则应该使用StringBuilder而不使用string

     


    family as water
    2010年12月21日 1:04
  • chinasnail 你好,

    欢迎来到MSDN论坛!

    之前Stone Z说的对。

    在你给出的例子当中,我们单独来看关于string的那部分代码:

    string str = "ab";
    string str1 = str;
    str =
    "abc";
    str1 =

    在这里str1的值还是ab,因为string对象是不可变的,包括长度和其中任何字符都是不可以改变的。
     

    虽然string是引用类型,但它是一种特殊的引用类型,每次使用string时,都要在内容中创建一个新的内存对象,即为该新对象分配新的,所以它的赋值可以按照值类型的赋值来处理。

     

    希望以上的解释对你有所帮助。

     Mio


    Mio Miao[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2010年12月27日 4:58
    版主
  • dear
    因为你摆的位置错误,你要str1改变
    你可更改下列两行的顺序。
    string str1 = str;
    str = "abc";

    改为
    str = "abc";
    string str1 = str;

    或是
    string str1 = str;
    str1 = "abc";

    这样str1就会变"abc"

    若您是要藉由str改变str1是不可以的,因为他门是不同的执行个体,string 类别只要一被赋予新的值,他就会重新建立一个新的执行个体,对于动态变更字串string效率是叫差的,您可参考小弟写的效能比较

    [Edit this entry.] [.NET] 動態處理字串 - StringBuilder 類別 與 String 類別的效能
    http://www.dotblogs.com.tw/yc421206/archive/2010/10/26/18575.aspx


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年12月27日 8:22
  • 我来说一点高级的吧,string 只是在正常情况下是不可变的 (immutable),但是,在某些情况下,它是可变的。

    大家可以研究一下最高效的 string 反转代码。就知道了。

    public unsafe void Reverse(string input)
    {
        int length = input.Length;

        fixed (char* p = input)
        {
            int i = 0;
            int j = input.Length - 1;

            while (i < j)
            {
                char temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;

                i++;
                j--;
            }
        }
    }       

    原理就是字符串的头和尾的字符对调。大家可以看到,返回值为 void,也就是直接用代码改变了输入的 string 参数。


    Mark Zhou
    2010年12月27日 10:43
  • 我来说一点高级的吧,string 只是在正常情况下是不可变的 (immutable),但是,在某些情况下,它是可变的。

    大家可以研究一下最高效的 string 反转代码。就知道了。

    public unsafe void Reverse(string input)
    {
        int length = input.Length;

        fixed (char* p = input)
        {
            int i = 0;
            int j = input.Length - 1;

            while (i < j)
            {
                char temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;

                i++;
                j--;
            }
        }
    }       

    原理就是字符串的头和尾的字符对调。大家可以看到,返回值为 void,也就是直接用代码改变了输入的 string 参数。


    Mark Zhou

    我觉得不应该这么做

    不排除以后c#为了优化性能,使得相同内容的string指向同一个地址的char*。

    而且这么做会破坏string的hash机制,如果string为了优化缓存了长字符串的hash值呢?或者这个string已经在hashset之类的容器之内呢。

    immutable和mutable的string的这是一个选择。既然C#选择了前者,一定要遵循。

    2010年12月28日 7:17

全部回复

  • string   对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因,如果经常改变string的值则应该使用StringBuilder而不使用string

     


    family as water
    2010年12月21日 1:04
  • chinasnail 你好,

    欢迎来到MSDN论坛!

    之前Stone Z说的对。

    在你给出的例子当中,我们单独来看关于string的那部分代码:

    string str = "ab";
    string str1 = str;
    str =
    "abc";
    str1 =

    在这里str1的值还是ab,因为string对象是不可变的,包括长度和其中任何字符都是不可以改变的。
     

    虽然string是引用类型,但它是一种特殊的引用类型,每次使用string时,都要在内容中创建一个新的内存对象,即为该新对象分配新的,所以它的赋值可以按照值类型的赋值来处理。

     

    希望以上的解释对你有所帮助。

     Mio


    Mio Miao[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2010年12月27日 4:58
    版主
  • dear
    因为你摆的位置错误,你要str1改变
    你可更改下列两行的顺序。
    string str1 = str;
    str = "abc";

    改为
    str = "abc";
    string str1 = str;

    或是
    string str1 = str;
    str1 = "abc";

    这样str1就会变"abc"

    若您是要藉由str改变str1是不可以的,因为他门是不同的执行个体,string 类别只要一被赋予新的值,他就会重新建立一个新的执行个体,对于动态变更字串string效率是叫差的,您可参考小弟写的效能比较

    [Edit this entry.] [.NET] 動態處理字串 - StringBuilder 類別 與 String 類別的效能
    http://www.dotblogs.com.tw/yc421206/archive/2010/10/26/18575.aspx


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年12月27日 8:22
  • 我来说一点高级的吧,string 只是在正常情况下是不可变的 (immutable),但是,在某些情况下,它是可变的。

    大家可以研究一下最高效的 string 反转代码。就知道了。

    public unsafe void Reverse(string input)
    {
        int length = input.Length;

        fixed (char* p = input)
        {
            int i = 0;
            int j = input.Length - 1;

            while (i < j)
            {
                char temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;

                i++;
                j--;
            }
        }
    }       

    原理就是字符串的头和尾的字符对调。大家可以看到,返回值为 void,也就是直接用代码改变了输入的 string 参数。


    Mark Zhou
    2010年12月27日 10:43
  • 我来说一点高级的吧,string 只是在正常情况下是不可变的 (immutable),但是,在某些情况下,它是可变的。

    大家可以研究一下最高效的 string 反转代码。就知道了。

    public unsafe void Reverse(string input)
    {
        int length = input.Length;

        fixed (char* p = input)
        {
            int i = 0;
            int j = input.Length - 1;

            while (i < j)
            {
                char temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;

                i++;
                j--;
            }
        }
    }       

    原理就是字符串的头和尾的字符对调。大家可以看到,返回值为 void,也就是直接用代码改变了输入的 string 参数。


    Mark Zhou


    dear mark

    听君一席话胜过万卷书


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    2010年12月27日 11:48
  • 也就是说,实际上C#中的String也不是原生数据类型。而是在编译器级作了手脚而已。实际上还是跟C++的<string>一样,所有的地方都是对象引用罢了。 是这个意思吧:-)
    2010年12月28日 0:04
  • 我来说一点高级的吧,string 只是在正常情况下是不可变的 (immutable),但是,在某些情况下,它是可变的。

    大家可以研究一下最高效的 string 反转代码。就知道了。

    public unsafe void Reverse(string input)
    {
        int length = input.Length;

        fixed (char* p = input)
        {
            int i = 0;
            int j = input.Length - 1;

            while (i < j)
            {
                char temp = *(p + i);
                *(p + i) = *(p + j);
                *(p + j) = temp;

                i++;
                j--;
            }
        }
    }       

    原理就是字符串的头和尾的字符对调。大家可以看到,返回值为 void,也就是直接用代码改变了输入的 string 参数。


    Mark Zhou

    我觉得不应该这么做

    不排除以后c#为了优化性能,使得相同内容的string指向同一个地址的char*。

    而且这么做会破坏string的hash机制,如果string为了优化缓存了长字符串的hash值呢?或者这个string已经在hashset之类的容器之内呢。

    immutable和mutable的string的这是一个选择。既然C#选择了前者,一定要遵循。

    2010年12月28日 7:17
  • string 的 immutable 仅仅体现在托管代码层面,当然,在所有基于托管代码的实现中,必须保证 string 的不可变性。

    但在有些时候,比如,托管代码和非托管代码之间的交互,原生的 string 类型就必须被 fixed 之后再 pinned。这一点可以通过对 Interop 的代码进行 IL 反编译看到。这种情况下,要求托管 string 必须具备一个固定地址的指针 (fixed char*),否则无法支持其他非托管代码,如 C++ 的代码。

    毫无疑问,在任何只有托管代码的实现中,请保持 string 不可变;在任何特殊需要,如核心算法和 Interop 时,请考虑使用 fixed char*。

    楼上的 Charles Shao 的说法不是很准确,string 在设计时就是原生类型,是不可变类型t,只不过在某些时候可以让他可变。


    Mark Zhou
    2010年12月30日 7:44

  • __陈浩楠

    2018年1月8日 6:41