none
大家来看看,这道题答案是几?? RRS feed

  • 问题

  • class Class1 {
           private string str = "class1.str";
           private int i = 0;
           static void StringConvert(string str)  {
               str = "string being converted.";
           }
           static void StringConvert(Class1 c)  {
               c.str = "string being converted.";
           }
           static void Add(int i)  {
               i++;
           }
           static void AddWithRef(ref int i)  {
               i++;
           }
           static void Main()  {
               int i1 = 10;
               int i2 = 20;
               string str = "str";
               Class1 c = new Class1();
               Add(i1);
               AddWithRef(ref i2);
               Add(c.i);
               StringConvert(str);        
               StringConvert(c);
               Console.WriteLine(i1);
               Console.WriteLine(i2);
               Console.WriteLine(c.i);
               Console.WriteLine(str);
               Console.WriteLine(c.str);
               Console.Read();
           } 
        }
    输出答案是多少呢??我不懂为什么,希望大家给解释一下!!
    谢谢!!
    2009年6月17日 1:32

答案

  • 哦!原来是这里不明白啊!
    我给你解释一下,字符串的确是引用类型的,但是这个引用类型很特殊,他在行为上和值类型很类似,这实际上也是微软的设计目的,他的目的就是想让我们像使用值类型那样使用string类型!因为从一般常识来认识String就应该是值类型的!
    上面说的希望你能够理解,下面我针对这个问题做个解释:
    String就是引用类型的,但是很特殊,因为一旦字符串的值被修改,系统就会自动创建一个新的字符串对象,并使原来的字符串引用指向这个新创建的对象!
    比如:
    string s1="aaa";
    string s2=s1;     //这时s1和s2都是“aaa"
    s2="bbb";          //这时s2的值是"bbb",因为一旦字符串的值被修改,系统就会自动创建一个新的字符串对象,并使原来的字符串引用指向这个新创建的对象,而这时s1的值还是"aaa",这个行为和值类型很类似,实际上string绝对是引用类型!
    周雪峰
    • 已标记为答案 痴迷.Net 2009年6月20日 0:31
    2009年6月17日 12:15
    版主
  • 也许是我没有说清楚,这两个i我知道是这么回事,主要在两句话上面了,
               Console.WriteLine(str);
               Console.WriteLine(c.str);
    为什么不一样呢??
    字符串不是引用类型么??
    这个大家再解释一下!!

    谢谢!!


    hi,
       自己查询资料吧。我只能从IL来分析一下了,自己运行了一下,也做了几次修改。也算是我也学习了。我对你字符串部分的代码做了整理,分别是三个方法:
          1.  static void StringConvert(string str)
            {
                str = "string being converted.";
            }
           2. static void StringConvert(ref string str)
            {
                str = "string being converted.";
            }
           3. static void StringConvert(Class1 c)
            {
                c.strFeild = "string being converted.";
            }
    ,然后反汇编看IL:
    .method private hidebysig static void  StringConvert(string str) cil managed
    {
      // 代码大小       9 (0x9)
      .maxstack  8
      IL_0000:  nop//如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作。
      IL_0001:  ldstr      "string being converted."//推送对元数据中存储的字符串的新对象引用。
      IL_0006:  starg.s    str//从堆栈中弹出位于顶部的值并将其存储在参数槽 num 中。
      IL_0008:  ret//从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
    } // end of method Class1::StringConvert
    .method private hidebysig static void  StringConvert(class Fibonacci.Class1 c) cil managed
    {
      // 代码大小       13 (0xd)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldarg.0//将索引为 0 的参数值推送到堆栈上。
      IL_0002:  ldstr      "string being converted."//推送对元数据中存储的字符串的新对象引用。
      IL_0007:  stfld      string Fibonacci.Class1::str//用新值替换在对象引用或指针的字段中存储的值。
      IL_000c:  ret//从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
    } // end of method Class1::StringConvert
    .method private hidebysig static void  StringConvert(string& str) cil managed
    {
      // 代码大小       9 (0x9)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldstr      "string being converted."
      IL_0007:  stind.ref//存储所提供地址处的对象引用值。
      IL_0008:  ret
    } // end of method Class1::StringConvert

     你可以看出实际你的方法1.  static void StringConvert(string str),IL代码可以看出是没有创建或者对原来的引用修改的。所以内容没变。
    2. static void StringConvert(ref string str),IL代码可以看出用新值替换在对象引用或指针的字段中存储的值。

     3. static void StringConvert(Class1 c),//操作的是原来对象引用值。所以做了修改。
       以上是个人整理的,算是与你一起交流吧。此外其实字符串是个复杂的引用对象,深入学习的话还会涉及到.NET平台的底层机制,如字符串驻留等问题。
       你在自己学习的时候,自己查资料最好,找些权威的资料。国内的学习风气不如国外。灌水的太多了...

    Frank.Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    老徐的博客:http://frank_xl.cnblogs.com
    • 已标记为答案 痴迷.Net 2009年6月20日 0:31
    2009年6月17日 17:19
    版主

全部回复

  • 答案你运行就知道啦,主要是要了解函数传值和地址的区别
    http://feiyun0112.cnblogs.com/
    2009年6月17日 1:54
    版主
  • 我就是想问问里面主要的关键点,至于答案我也晓得运行就可以的~~~
    2009年6月17日 2:34
  • 你好!
         关键点是这里:
           static void Add(int i)  {        //这个是按值传递参数,在函数里对参数的修改不会影响原来传入的那个变量
               i++;
           }
           static void AddWithRef(ref int i)  {        //这个是按引用传递参数,在函数里对参数的修改会影响原来传入的那个变量
               i++;
           }
    周雪峰
    2009年6月17日 5:09
    版主
  • 你好,主要讲的是怎么样本来是值传递的,实现引用传递,就是添加一个关键字rel。
    邹俊才
    2009年6月17日 5:53
    版主
  • 也许是我没有说清楚,这两个i我知道是这么回事,主要在两句话上面了,
               Console.WriteLine(str);
               Console.WriteLine(c.str);
    为什么不一样呢??
    字符串不是引用类型么??
    这个大家再解释一下!!

    谢谢!!

    2009年6月17日 10:08
  • 哦!原来是这里不明白啊!
    我给你解释一下,字符串的确是引用类型的,但是这个引用类型很特殊,他在行为上和值类型很类似,这实际上也是微软的设计目的,他的目的就是想让我们像使用值类型那样使用string类型!因为从一般常识来认识String就应该是值类型的!
    上面说的希望你能够理解,下面我针对这个问题做个解释:
    String就是引用类型的,但是很特殊,因为一旦字符串的值被修改,系统就会自动创建一个新的字符串对象,并使原来的字符串引用指向这个新创建的对象!
    比如:
    string s1="aaa";
    string s2=s1;     //这时s1和s2都是“aaa"
    s2="bbb";          //这时s2的值是"bbb",因为一旦字符串的值被修改,系统就会自动创建一个新的字符串对象,并使原来的字符串引用指向这个新创建的对象,而这时s1的值还是"aaa",这个行为和值类型很类似,实际上string绝对是引用类型!
    周雪峰
    • 已标记为答案 痴迷.Net 2009年6月20日 0:31
    2009年6月17日 12:15
    版主
  • 也许是我没有说清楚,这两个i我知道是这么回事,主要在两句话上面了,
               Console.WriteLine(str);
               Console.WriteLine(c.str);
    为什么不一样呢??
    字符串不是引用类型么??
    这个大家再解释一下!!

    谢谢!!


    hi,
       自己查询资料吧。我只能从IL来分析一下了,自己运行了一下,也做了几次修改。也算是我也学习了。我对你字符串部分的代码做了整理,分别是三个方法:
          1.  static void StringConvert(string str)
            {
                str = "string being converted.";
            }
           2. static void StringConvert(ref string str)
            {
                str = "string being converted.";
            }
           3. static void StringConvert(Class1 c)
            {
                c.strFeild = "string being converted.";
            }
    ,然后反汇编看IL:
    .method private hidebysig static void  StringConvert(string str) cil managed
    {
      // 代码大小       9 (0x9)
      .maxstack  8
      IL_0000:  nop//如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作。
      IL_0001:  ldstr      "string being converted."//推送对元数据中存储的字符串的新对象引用。
      IL_0006:  starg.s    str//从堆栈中弹出位于顶部的值并将其存储在参数槽 num 中。
      IL_0008:  ret//从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
    } // end of method Class1::StringConvert
    .method private hidebysig static void  StringConvert(class Fibonacci.Class1 c) cil managed
    {
      // 代码大小       13 (0xd)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldarg.0//将索引为 0 的参数值推送到堆栈上。
      IL_0002:  ldstr      "string being converted."//推送对元数据中存储的字符串的新对象引用。
      IL_0007:  stfld      string Fibonacci.Class1::str//用新值替换在对象引用或指针的字段中存储的值。
      IL_000c:  ret//从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
    } // end of method Class1::StringConvert
    .method private hidebysig static void  StringConvert(string& str) cil managed
    {
      // 代码大小       9 (0x9)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldstr      "string being converted."
      IL_0007:  stind.ref//存储所提供地址处的对象引用值。
      IL_0008:  ret
    } // end of method Class1::StringConvert

     你可以看出实际你的方法1.  static void StringConvert(string str),IL代码可以看出是没有创建或者对原来的引用修改的。所以内容没变。
    2. static void StringConvert(ref string str),IL代码可以看出用新值替换在对象引用或指针的字段中存储的值。

     3. static void StringConvert(Class1 c),//操作的是原来对象引用值。所以做了修改。
       以上是个人整理的,算是与你一起交流吧。此外其实字符串是个复杂的引用对象,深入学习的话还会涉及到.NET平台的底层机制,如字符串驻留等问题。
       你在自己学习的时候,自己查资料最好,找些权威的资料。国内的学习风气不如国外。灌水的太多了...

    Frank.Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    老徐的博客:http://frank_xl.cnblogs.com
    • 已标记为答案 痴迷.Net 2009年6月20日 0:31
    2009年6月17日 17:19
    版主
  • 感谢以上俩位的解答,似乎明白又似乎迷糊,估计是这个string太麻烦了吧!
    O(∩_∩)O~
    2009年6月20日 0:30
  • 你可以看看我的解释,更通俗一些啊!
    Xu版主描述的太深了些,可能不适合初学者啊!
    周雪峰
    2009年6月20日 8:06
    版主