1

对不起,我不太擅长解释问题。我可以通过以下示例更好地解释我的问题:

string first = "hello";
string second = "Bye";
first = second;

在上面的例子中,考虑第三行first=second
在这里,我将第二个对象分配给第一个对象。因为 c# 中的字符串是不可变的,即每次您为现有字符串对象分配新值时,都会创建一个新对象并由 CLR 释放旧对象。(我从这里读到这个​​1)。所以简单地说,第一行的对象与第三行 的first对象不同。所以我的问题是我怎样才能证明两者是不同的? 即如果it(string) 在C 中是可能的,那么我可以在第三条语句之前和之后打印两个对象的地址来证明它。有什么方法可以访问那里的地址或其他替代方法吗?first



4

6 回答 6

5

如果您想查看内存中的物理位置,可以使用以下(不安全)代码。

private static void Main(string[] args)
{
  unsafe
  {
    string first = "hello";

    fixed (char* p = first)
    {
      Console.WriteLine("Address of first: {0}", ((int)p).ToString());
    }

    string second = "Bye";

    fixed (char* p = second)
    {
      Console.WriteLine("Address of second: {0}", ((int)p).ToString());
    }

    first = second;

    fixed (char* p = first)
    {
      Console.WriteLine("Address of first: {0}", ((int)p).ToString());
    }
  }
}

我机器上的示例输出:

Address of first: 41793976 
Address of second: 41794056
Address of first: 41794056

您会注意到,.NET 缓存了完全有效的字符串实例,因为它们是不可变的。为了演示此行为,您可以更改secondhello所有内存地址都将相同。这就是为什么您不应该依赖本机内存而只使用托管方式来处理对象的原因。

也可以看看:

公共语言运行时通过维护一个称为实习池的表来保存字符串存储,该表包含对程序中以编程方式声明或创建的每个唯一文字字符串的单个引用。因此,具有特定值的文字字符串的实例在系统中只存在一次。

资料来源: String.Intern (MSDN)

于 2013-10-14T06:55:24.337 回答
3

我相信你想要ReferenceEquals方法。它可以用来检查对象的两个实例是否完全相同——即引用同一个对象。

于 2013-10-14T06:50:35.243 回答
1

为此,您应该在分配第二个变量之前获取第一个变量的内存地址,并在分配后再次检查内存地址。

要获取字符串的地址,请点击此链接

这可以帮助你吗

于 2013-10-14T07:06:25.510 回答
1

如果您必须比较底层内存地址,以下不安全代码可能会对您有所帮助(未经测试):

string first = "hello";


GCHandle handle = GCHandle.Alloc(first, GCHandleType.Pinned);
IntPtr address = handle.AddrOfPinnedObject();


string second = "Bye";
first = second;


GCHandle handle = GCHandle.Alloc(first, GCHandleType.Pinned);
IntPtr address2 = handle.AddrOfPinnedObject();

if (address != address2)
{
    // memory addresses are different afterwards
}
于 2013-10-14T06:54:15.643 回答
1

你误解了你所读的内容。是的,字符串是不可变的。这意味着您不能更改现有字符串。这不起作用

string x = "Hello";
x[3] = 'q';

当你连接字符串时,你会得到一个新的:

string a = "a";
string b = "b";
string c = a+b; // You get a new string and a and b are unchanged.

即使你是自连接的,你也会得到一个新的字符串:

string a = "a";
a += "b"; // The same as a = a + "b" and yields a new string.

但是分配给变量(或传递给函数,或从函数返回等)不会创建新字符串。

字符串是“引用类型”。这意味着这个变量:

string a = "Hello";

只是对字符串的引用。这样做:

string b = a;

只需将引用分配给变量。它不会改变字符串。

或者,用 C 语言来说:引用变量是指向对象的指针。考虑:

string a = "Hello"; // a now points to the string object
string b = a; // b now points to the same object.

不变性意味着您不能更改指针指向的内存(字符串对象本身)。但是指针变量和以往一样多变。您可以为其分配不同的地址。

回到你原来的例子:

string first = "hello"; // Allocates memory for "hello" and points first to it.
string second = "Bye";  // Allocates memory for "Bye" and points second to it.
first = second;         // Assigns the address of second to first.

最后,first和都second指向同一个地址,也就是字符串的地址Bye。字符串的内存hello现在未被引用(没有指向它的指针,它无法访问)。垃圾收集器稍后会回收它。

补充:另一个与 C 的类比。字符串变量 .NET 有点像这样:

const char* str;

它是一个指向常量的指针。您可以更改指针,但不能更改它指向的内容。

补充 2:您应该阅读 .NET 中的值类型与引用类型。简而言之,值类型都是struct类型,引用类型都是class类型。值类型在赋值时被复制(或从函数传递/返回时);引用类型是指针。

请注意,这里有一个不直观的部分。classobject是所有类型的基类,是引用类型。然而,值类型继承自它,您可以将值类型分配给 type 的变量object。如果你这样做,这将导致一种称为装箱的事情,它涉及复制值,所以它有点昂贵的操作。

于 2013-10-14T07:05:20.967 回答
1

*可以用.Equals()方法或HashCode()方法来比较 *

于 2013-10-14T06:45:54.233 回答