根据文档,类型System.String
在设计上是不可变的。因此,当尝试连接字符串等时,我们只获得对结果字符串的引用。但是如果这是真的,为什么这个代码总是为两种情况返回相同的地址(当然,如果对象没有被GC移动):
using System;
using System.Reflection;
namespace StringImmutabilityCheck
{
class Program
{
private static unsafe void PrintAddress(string b)
{
var info = typeof(string).GetField("m_firstChar", BindingFlags.Instance | BindingFlags.NonPublic);
char value = (char)info.GetValue(b);
char* buffer = &value;
Console.WriteLine("Addres of {0} is {1}", b, (int)buffer);
}
static void Foo(ref string a)
{
a += "xxx";
}
static void Main()
{
string b = "aaaa";
PrintAddress(b);
Foo(ref b);
PrintAddress(b);
}
}
}
答案 0 :(得分:3)
因为你正在编写局部变量c
的地址,它在堆栈上的位置都是相同的。
请注意m_firstChar
不是地址;它是第一个char 。在内部,代码使用相对于对象的第一个char的地址来访问数据,但是:m_firstChar
将在这里报告'a'
这两种情况,因为{{1是字符串中的第一个字符。
真正有趣:
'a'
现在"地址"不同的用于相同的字符串。
答案 1 :(得分:3)
你不在这里获取字符串的地址
char value = (char)info.GetValue(b); // 'value' is a local var
char* buffer = &value; // buffer points to local var, on the stack
Console.WriteLine("Addres of {0} is {1}", b, (int)buffer); // no it isn't
答案 2 :(得分:0)
尝试使用此函数获取字符串的地址:
Func<string, int> getAddress = x =>
{
unsafe
{
fixed (char *p = x)
{
return (int)p;
}
}
};
然后,这可用于查看地址更改:
var text = "Foo";
Console.WriteLine(getAddress(text));
text += "Bar";
Console.WriteLine(getAddress(text));
请注意,当您使用它时,GC可能会移动字符串。