先看下面: 原贴引用using System;class Class1 

    static void StrChange(string str) 
    { 
      str = "hellow"; 
    }     static void Main() 
    { 
      string str = "123";//申明一个字符串 
      StrChange(str);//调用方法 
      Console.WriteLine(str);//输出字符串 
    } 

//输出123
再看下面:using System;class String
{
    private string myString;    public String(string myString)
    {
        this.myString = myString;
    }    public override string ToString()
    {
        return myString.ToString();
    }}class Class1
{
    static void StrChange(String str)
    {
        str = new String("hellow"); 
    }    static void Main()
    {
        String str = new String("123");//申明一个字符串 
        StrChange(str);//调用方法 
        Console.WriteLine(str);//输出字符串 
        Console.ReadKey();
    }
}
//输出123
坚持string类型“特殊”说的大有人在,
比如string具有Immutable的特性,
从第二个案例来看,好象跟一般的引用类型没啥两样的,彻底晕了。先热一下身,一会再势出一个“NEW 构造函数 阻断说”的理论~~~

解决方案 »

  1.   

    你需要理清楚四个基础概念:1. 引用类型.
    2. 值类型.
    3. 传引用.
    4. 传值. 另外你还可以google "C++ 传指针 传指针的指针".
      

  2.   


    引用类型可以传值调用,值类型也可以引用调用,楼主不要将类型与调用搞混了。C#中,string 的确“特殊”,因为 string 是 Class,Class 是引用类型。参考MSDN中的说明:string 类型表示零或更多 Unicode 字符组成的序列。string 是 .NET Framework 中 String 的别名。
    尽管 string 是引用类型,但定义相等运算符(== 和 !=)是为了比较 string 对象(而不是引用)的值。这使得对字符串相等性的测试更为直观。再看看 C# 中 String 的定义:
    public sealed class String : IComparable, ......即 string 是一个密闭类。再看看其它的基本类型,如: int
    int 在 .NET 中的类型是 System.Int32 System.Int32 的定义呢:
    public struct Int32 : IComparable, ......
    这是一个结构,结构是值类型。
      

  3.   

    子类重写String. 有什么晕的.
      

  4.   

    有啥晕的,string的传值方式是有点特殊啊
      

  5.   

    1.string是特殊的引用类型,这是毫无疑问的...2.那个引用帖子里产生的理解错误和string毫无关系,这也是毫无疑问的...在那个引用帖子里不少人都给出了正确的答案和解释...但是因为该帖楼主错误标题的误导和新人回帖不看帖的传统恶习,很多人仍然在string的特殊性、构造函数甚至override等不想干的概念上瞎扯...
      

  6.   

    楼主我晓得你的意思??你是说,第二个例子是你自己定义的String类型,,把它当做一般的普通引用类型来做比较。。但是你存在一个误区,,你自己定义的String仍然使用了.net中的string 类型定义字段,以及处理。。实质还是一样。结果自然也是那样。。楼上的大虾已经把string类型怎么个特殊都列出来了,,记住就可以了。。
      

  7.   

    原来那个帖子的问题不仅仅是对 string 类型,对一般的引用类型也是如此,并不是因为 string 的不可变性,而是因为没有使用 ref 关键字。即使把原贴中的 string 换成可变的 StringBuilder 结果也是一样的。
      

  8.   

    string是引用类型,但具有值类型的特点!
      

  9.   

    楼主你第二个例子的输出结果写错了。string是引用类型,本来第一个例子是可以改变引用类型内容的,但由于string是不可变的,因此在程序中会创建一个新的string,而并不会更改本身的内容。
    第二个例子是改变引用类型的引用,相当于将传入的string指向了另一个string,自然也就看起来像是改变了其内容。
      

  10.   

    14楼的说法正确,当string类型作为参数传入方法时,实际上是创建一个新的string类型复制原来的值传入
      

  11.   

    在参数前加上ref就能输出"hellow"
      

  12.   

    楼上还有很多人说到"特殊"两字.
    string类是很普通的引用类型,概念上一点都不特殊!
      

  13.   


    string 是引用类型,相等运算符(== 和 !=)是比较 string 对象的值!
    普通引用类型,相等运算符(== 和 !=)是比较是否是同一对象(即引用)。string 特殊,指的就是这个。
      

  14.   

    string是引用类型,第一个例子中传进去的也确实是引用。这就是说这个时候 Main 方法和 StrChange 方法的str 都是指向同一个实例的。
    但问题出在接下来的赋值上 
    str = "hellow";
    相当于java的 str=new String("hellow");
    也就是说 StrChange 内的 str 指向了一个新的实例。而不是改变了str原来实例的内容。
    String实例的内容是永远也不会改变的。
    这就是为什么有了 String 类还要来个 StringBuilder 类的原因。
      

  15.   


        public class Program
        {
            static void StrChange(StringBuilder str)
            {
                str.Remove(0, str.Length);
                str.Append("hellow");
            }         static void Main(string[] args)
            {
                StringBuilder str = new StringBuilder("123");//申明一个字符串 
                StrChange(str);//调用方法 
                Console.WriteLine(str);//输出字符串
                //显示 hellow
            }
        }
      

  16.   

    倒,按空军的说法要 ref str才能输出hellow吧
      

  17.   

    我说的是把 string 换成可变的 StringBuilder 结果也是一样的。 using System;
    using System.Text;class Class1 

        static void StrChange(StringBuilder str) 
        { 
          str = new StringBuilder("hellow"); 
        }     static void Main() 
        { 
          StringBuilder str = new StringBuilder("123");//申明一个字符串 
          StrChange(str);//调用方法 
          Console.WriteLine(str);//输出字符串 
        } 

    //输出123
    而不是说:       static void StrChange(StringBuilder str)
            {
                str.Remove(0, str.Length);
                str.Append("hellow");
            } 
      

  18.   

    C#是微软的产品,不用细究C#里的string是如何与你所了解的ref type有何不同--有需要就上微软的网站查。用.NET就遵守微软的定义就行了。.NET和C#是用来做商业开发的,并不是适合做理论研究的平台。纯理论的用纯的C/C++平台。
      

  19.   

    按楼主的代码,是要加ref才可以呀。
    你的代码其实是修改参数的数据,而不是修改的参数本书。其实你说的也没错,对。
      

  20.   

    你把2个str  一个用str1 一个 str2 就明白了
      

  21.   

    ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。例如:C#  复制代码 
    class RefExample
    {
        static void Method(ref int i)
        {
            i = 44;
        }
        static void Main()
        {
            int val = 0;
            Method(ref val);
            // val is now 44
        }
    } 上面是msdn里的,什么是对参数的修改?就是对参数本身赋值,比如这个例子里的i=xxx,楼主的str=xxx。这跟数据类型是值还是引用类型没有关系,有人老把这些混在一起。
    没有ref时:
    值类型参数,对参数赋值无效(指不能影响到方法外部)。
    引用类型参数,对参数赋值无效,但是可以通过访问对象的成员来改变某些成员的值,这可以影响到方法外部。
    有ref时:
    值类型参数,对参数赋值有效。
    引用类型参数,对参数赋值有效,但这时已经不是原来的对象了;也可以通过访问对象的成员来改变某些成员的值,这可以影响到方法外部;对象还是原来的对象。
      

  22.   

    CSDN上说的清楚,学的人家的东西,人家说什么就是什么喽!可以去看看!地址http://msdn.microsoft.com/zh-cn/library/system.string.aspx
      

  23.   

    [1]有感
    终于回到家中了,看到:
    热闹了两天,后来就没戏了。
    我想可能多数人“以为”问题己经清楚,到此为止了吧。[2]说明
    我得承认,做了一回标题党“彻底晕了!”,其实我一点也不晕。
    自打看到“原贴”后,发现自己对一些原本认为很“基础”的东西,原来并不真正的了解。
    嗯,同样说来,其实一知半解的还是大有人在,所以很想把“心得”交流一下。
    特别是想,论坛里有很多说法存在“严重错误”有必要澄清一下,以正视听。[3]评论
    1、6、13、16、17楼:酱油型或是还没有理解问题或是没有任何价值的评论
    3、11、20楼:扔一些概念,但没有说明问题
    4、19、22楼:画蛇添足,解说部分与问题毫不相干
    7、14、18楼:误导的受害者,string特殊的结果
    8楼:没说错,但也算酱油,没有新鲜的内容
    10、23楼:我会给你新的例子,说明这个并不是问题的关键
    11楼:第一个出来解决问题的人,首先提出用StringBuilder来替换,正好可以解决一下10楼的疑惑
    15楼:很奇怪的矛盾,前半段是错误的,后半段还有点道理,不知道是否真的理解了
    20楼:强化观点,没有进一步的说明
    21楼:基本说对了,如果能进一步讲清楚函数体内关于NEW赋值的部分就完整了。
    其余了不再一一罗列了,呵呵[4]看代码是最好的办法,加上几组概念
    形参、值参
    值类型、引用类型
    传值、传引用
    栈、堆
    隐式转换
    装箱using System;
    using System.Text;
    class Class1
    {
        static void StrChange(StringBuilder str)
        {
            Console.WriteLine("内部调用0:{0}", str);//形参不变(指向的实体不变123),实参不变(指向的实体不变123)
            str.Replace("123", "hellow");
            Console.WriteLine("内部调用1:{0}", str);//形参不变(指向的实体改变hellow),实参不变(指向的实体改变hellow)
            str = new StringBuilder("hellowNEW");
            Console.WriteLine("内部调用2:{0}", str);//形参改变(指向的实体改变hellowNEW),实参不变(指向的实体不变hellow)
            str.Replace("hellowNEW", "hellowNEW123");
            Console.WriteLine("内部调用3:{0}", str);//形参不变(指向的实体改变hellowNEW123),实参不变(指向的实体不变hellow)
        }
        static void Main()
        {
            StringBuilder str = new StringBuilder("123");//申明一个字符串,实参
            StrChange(str);//调用方法
            Console.WriteLine("外部调用0:{0}", str);//输出字符串,实参不变(指向的实体最后一次改变为hellow)
            Console.ReadKey();
        }
    }
    [5]要觉觉了,其余明天再说~~
      

  24.   


    string 类重载了比较操作运算符,
    先比较是否同一个引用,如果不是同一个引用再比较值是否一致.
      

  25.   


    using System;class Class1 

        static void StrChange(string str) 
        { 
          str = "hellow"; 
        }     static void Main() 
        { 
          string str = "123";//申明一个字符串 
          StrChange(str);//调用方法 
          Console.WriteLine(str);//输出字符串 
        } 

    //输出123
    上述命题可以转化为下列“等价”命题using System;internal class ClassB
    {
        private string str;
        public ClassB(string str)
        {
            this.str = str;
        }
        public void PrintVal()
        {
            Console.WriteLine(str);
        }
    }class Test
    {
        static void Main()
        {
            ClassB a = new ClassB("123");
            ClassB b = a;
            a = new ClassB("hellow");
            b.PrintVal();        Console.ReadKey();
        }
    }
    //输出123
    需要进一步进行验证,可看以下案例using System;
    using System.Text;
    class Class1
    {
        static void StrChange(StringBuilder str)
        {
            Console.WriteLine("内部调用0:{0}", str);//形参不变(指向的实体不变123),实参不变(指向的实体不变123)
            str.Replace("123", "hellow");
            Console.WriteLine("内部调用1:{0}", str);//形参不变(指向的实体改变hellow),实参不变(指向的实体改变hellow)
            str = new StringBuilder("hellowNEW");
            Console.WriteLine("内部调用2:{0}", str);//形参改变(指向的实体改变hellowNEW),实参不变(指向的实体不变hellow)
            str.Replace("hellowNEW", "hellowNEW123");
            Console.WriteLine("内部调用3:{0}", str);//形参不变(指向的实体改变hellowNEW123),实参不变(指向的实体不变hellow)
        }
        static void Main()
        {
            StringBuilder str = new StringBuilder("123");//申明一个字符串,实参
            StrChange(str);//调用方法
            Console.WriteLine("外部调用0:{0}", str);//输出字符串,实参不变(指向的实体最后一次改变为hellow)
            Console.ReadKey();
        }
    }
      

  26.   

    楼上的不厚道啊.
    //首先我承认你,己经能够理解问题了.不过:我看你在"原贴"中的解说更加的复杂
    关键:除了有人扔下一两个概念后,没有一个人把问题解说的明明白白.
    更何况:还有各种各样,扰乱视听的说法,和复杂的解释[1]string是值类型(这严重错误的人,并不多)
    [2]string是特殊的引用类型(这个倒是不错,只是跟问题的本质无关)
    [3]string是特殊的引用类型,它的实例是只读的
    [4]string好像具有不变性
    [5]函数内str所指内存,未改变函数外str(废话)
    [6]string是引用类型,是不可变的,所以...
    [7]string类型确实是比较特殊的引用类型 
    [8]重载了Equals,= 等(想当然)
    [9]这个应该跟 C++ 指针参数类似。在 C# 里,除非声明为 ref (那是另一个问题)
    [10]string是经过特殊处理了
    [11]string是特殊的引用类型,它的实例是只读的(那又怎么样)3
    [12]他的值是只读的 (听上去有道理,然后呢)
    [13]楼主还是先去把变量的作用范围那块书看看吧(好象比谁都懂)
    [14]immutable特性 (这是我犯的错误)
    [15]你的string并没有new
    [16]IL代码登场了(拜托,IL不是汇编,其实还是代码,只不过换一种写法嘛)
    [17]引用但对 '='较为特殊而已....简单和复杂本就是相对的还有很多抨击"lz的功底不到家"的家伙,更是可笑. 
      

  27.   

    呵呵,楼主,其实你这种精神还是很值得学习的,我也知道你已经弄明白了。
    这个问题的争论,也不是一次两次的了。但还是有很多人老是弄不明白,从回帖中也可以看出来,除了wuyi8808和vrhero,没有几个能说到点子上的。都是微软的什么值类型、引用类型、按值传递、按引用传递这几个名词闹的,哈哈。
      

  28.   

    是啊,呵呵
    只是lz指的是原贴的“楼主”,不是我。顺便有感而发:
    越是基础的内容,越是不容易把握,我想原因有这么几点:
    [1]很多人自以为(我括我),在没有经历过“问题”时,一般也就突略过去了。
    [2]基础内容的特殊性,反映了不规范的场景,不是所有人都会在意的。
    [3]基础的东西,有时候不太好通过假调的方法来验证,需要理论知识。
    [4]微软的有意回避,最多建议不采用而己。
    [5]有些案例或说明不规范,造成了误导。以上5种情况,对本案例来说,全部存在:
    比如说第[4]条,微软只抛下一句:Violates rule DoNotPassTypesByReference. 
    所以很难找到有关于引用类型的按引用传递的说明。
    再比如经典书《C#3.0》第五版中,只对值类型的值|ref|out,传递方式做了详细的说明,同样忽略了引用类型。
    其实最严重的是第[5]种情况,
    出自于一些很高级的作者,书藉,不再一一列举(呵呵,主要是没有底气)...在CSDN中,
    浮燥的人比比皆是,
    认真做研究的,少之又少,
    倒不是水平问题,主要还是在于态度,
    不喜欢验证,不喜欢用代码来说明问题,随意猜测的胡乱回答的更多,
    自己不明白,随意攻击提问者的真不少.呵呵,我是C#的初学者,刚刚入门,所以问题多一点.
    csdn得好好学习一下cnblogs,虽然有点差异...