【问题标题】:Why string address still the same after modification为什么修改后字符串地址还是一样
【发布时间】:2014-07-08 03:28:43
【问题描述】:

根据文档,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);
        }
    }
}

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    没有在这里得到字符串的地址

    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】:

      因为你写的是局部变量c的地址,两次都在栈上的相同位置。

      注意m_firstChar 不是地址;它是第一个字符。在内部,代码使用相对于对象的第一个字符的 地址 来访问数据,但是:m_firstChar 在这两种情况下都会报告'a',因为'a' 是第一个字符在字符串中。

      为了真正的乐趣:

      [MethodImpl(MethodImplOptions.NoInlining)]
      static void PassThru(string b)
      {
          PrintAddress(b);
      }
      
      ...
      PrintAddress(b);
      PassThru(b);
      

      现在“地址”不同了同一个字符串

      【讨论】:

        【解决方案3】:

        尝试使用此函数获取字符串的地址:

        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 可能会在您使用时移动字符串。

        【讨论】:

        • @leppie - 为什么不呢?除非我认为这段代码需要在我需要的方法之外使用,否则我更喜欢使用委托。将所有代码很好地结合在一起。
        猜你喜欢
        • 2020-09-02
        • 1970-01-01
        • 2020-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多