using System;
using System.Collections.Generic;
using System.Text;namespace tttt
{
    class Program
    {
        static void Main(string[] args)
        {
            string s1 = "Test";
            string s2 = "Test";            
            string s3 = string.Copy(s2);
   
            Console.WriteLine(s1 == s2);
            Console.WriteLine(s2 == s3);
            Console.WriteLine((object)s1 == s2);
            Console.WriteLine((object)s2 == s3);
          
            Console.Read();        }
    }
}
大家请看如上程序,我的问题主要出在第三个输出语句,为什么在机子上运行第三个输出语句输出的是True,我的理解是S1在(object)后已经变成了引用类型了按理来说S1与S2比的是引用的比较也就是说比较是不是指向同一个实例而S1它被赋值为TEST,S2也是被赋值为TEST这两个变量接理来说是不一样的呀,如果从比较引用的角度上看。如果从比较值的内容角度上它们是相等的,所以说第一和第二两个输出都是TRUE。
还有就是请问一下大家怎么才能在VS2005中知道一个变量的地址呀?
谢谢了!

解决方案 »

  1.   

    你说得对,S1在(object)后已经变成了引用类型了.
    之所以   Console.WriteLine((object)s2 == s3);输出的是FALSE,是因为他们的地址不一样.
    而Console.WriteLine((object)s1 == s2);的输出是TRUE,是因为s1与s2在编译后实际上是指向同一个地址.(编译器优化)
      

  2.   

    在C#中只有当使用unsafe环境才可以像C++一样直接访问变量地址(* 、&)
    为了调用非托管的DLL,提供了间接的访问变量地址的功能
    参考如下代码:[DllImport("kernel32.dll")]
    static extern bool ReadProcessMemory(uint hProcess, IntPtr lpBaseAddress,
       IntPtr lpBuffer, uint nSize, ref uint lpNumberOfBytesRead);[DllImport("kernel32.dll")]
    static extern uint GetCurrentProcess();private void button1_Click(object sender, EventArgs e)
    {
        int[] i = { 1234 };
        IntPtr vBaseAddress = Marshal.UnsafeAddrOfPinnedArrayElement(i, 0);
        byte[] vBuffer = new byte[4];
        IntPtr vBytesAddress = Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer, 0);    uint vNumberOfBytesRead = 0;
        ReadProcessMemory(GetCurrentProcess(), vBaseAddress,
            vBytesAddress, 4, ref vNumberOfBytesRead);
        int vInt = Marshal.ReadInt32(vBytesAddress);
        Text = vInt.ToString();
    }方法UnsafeAddrOfPinnedArrayElement()
    可以得到一个数组第N个元素的地址-_-!!!更多资料参考MSDN
      

  3.   

    TO:y1x12z8(烈火之剑) 
    你说的我还是有点不明白,麻烦这位大哥你能不能再说清楚点为什么说前者即  Console.WriteLine((object)s2 == s3);S2与S3指的地址是不一样的呀!
    而后者Console.WriteLine((object)s1 == s2);S1与S2指的地址又是一样的呀!
    在我看来,我认为后者在这种情况下S1="TEST"与S2="TEST"好像已经是生成两个不同的变量,他们分别都是指向一个名叫“TEST"的空间所以说你说的太简单了,小弟愚钝请高手指明!谢了!
      

  4.   

    Console.WriteLine((object)s1 == s2);输出为True,这种机制叫做字符串驻留,将两个值相等的字符串引用指向同一个变量。
    p.s.  String直接继承自Object,本身就是引用类型。
      

  5.   

    TO:ivorstar(单击此处留言)
    那为什么 Console.WriteLine((object)s2 == s3);却是FALSE,我觉的你们说的太过于表面话了,也许是我自己的知识水平有限所造成的,所以你们说的这些从表面上看我懂但实际操作运行评估结果时都是错的,所以我想知道怎么判断是字符串驻留,以免以后遇到时又做错了!
      

  6.   

    ((object)s2 == s3);为false是因为你显式的做了一个“TEST”的副本,地址自然不一样,而((object)s1 == s2)为true是因为CLR在初始化时,会创建一个内部的散列表存放字符串,JIT编译器编译方法时会查找这个散列表,如果字符串在表中,则将变量指向该地址,否则将字符串加入到散列表。注意是JIT编译器做的优化,而非C#编译器。
      

  7.   

    TO:ivorstar(单击此处留言)
    你的意思是说比如我给一个字符串变量赋了一个值“TEST”,然后我只要不要用STRING.COPY来进行赋值,还是一样用显式的赋一个相同内容的值“TEST”给别一个变量的话,在CLR的初始化时,JIT编译器从散列表中找字符串,因为找到了一个名为“TEST”的字符串,将他赋给第一个变量,然后在第二个变量在找时一样找到表中已经存在的个名为“TEST”内容的值这时它就不再创建而是直接向这个内容是吗?对于这方面的知识,我还要看那一些书,请高手指点一下书名!
      

  8.   

    string 是 class!本身就是引用类型!string 对象是不可改变 - 字符串对象一旦创建,其内容就不能更改!每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间string 对象的 == 运算符和两个不同引用类型的 == 运算符是不一样的!尽管 string 是引用类型,但定义相等运算符(== 和 !=)是为了比较 string 对象(而不是引用)的值多看看MSDN...
      

  9.   

    TO:vrhero(这个家伙很懒...) 
    不好意思,你所说的我清楚但对于这句话:每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间
    你的意思是不是说如果不用System.String 类中的方法之一,就不会给新创建的对象分配空间呀!
      

  10.   

    你的意思是不是说如果不用System.String 类中的方法之一,就不会给新创建的对象分配空间呀!
    --------------------------
    string 的 == 运算符是重载的方法,当然也是 System.String 类中的方法之一string a = "1" //分配空间
    a = "2"        //还要分配空间,此时值"2"的引用是值"1"的引用的“副本”understand?