在这种情况下,为什么C#使用相同的内存地址?

hov*_*jan 6 c# .net-core

当我执行这段代码

class Program
    {
        static void Main(string[] args)
        {
//scope 1 
            {
                string x = "shark";
                string y = x.Substring(0);
                unsafe
                {
                    fixed (char* c = y)
                    {
                        c[4] = 'p';
                    }
                }
                Console.WriteLine(x);
            }
//scope 2
            {
                string x = "shark";
//Why output in this line "sharp" and not "shark" ?
                Console.WriteLine(x);
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

输出为:

sharp
sharp
Run Code Online (Sandbox Code Playgroud)

当我在这样的方法中将这两个范围分开时:

class Program
    {
        static void Main(string[] args)
        {
            func1();
            func2();
        }
        private static void func2()
        {
            {
                string x = "shark";
                Console.WriteLine(x);
            }
        }

        private static void func1()
        {
            {
                string x = "shark";
                string y = x.Substring(0);
                unsafe
                {
                    fixed (char* c = y)
                    {
                        c[4] = 'p';
                    }
                }
                Console.WriteLine(x);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

输出为:

sharp
shark
Run Code Online (Sandbox Code Playgroud)

已编辑

我也尝试这样:

  class Program
    {
        static void Main(string[] args)
        {
            {
                string x = "shark";
                string y = x.Substring(0);
                unsafe
                {
                    fixed (char* c = y)
                    {
                        c[4] = 'p';
                    }
                }
                Console.WriteLine(x);
            }
            void Test(){
                {
                    string x = "shark";
                    Console.WriteLine(x);
                }
            }
            Test();
        }
}
Run Code Online (Sandbox Code Playgroud)

输出为:

 sharp
 shark
Run Code Online (Sandbox Code Playgroud)

**我使用的环境是MacOS和.net core 2.2(Rider)**

我希望在所有情况下都具有相同的输出,但是输出是不同的。众所周知,实习是将您所有硬编码的字符串放入汇编中,并在整个应用程序中全局重用,以重用相同的内存空间。但是在此代码的情况下,我们看到

硬编码的字符串仅在函数范围内而不在全局范围内重用

这是.NET Core错误还是有解释?

在此处输入图片说明 在此处输入图片说明

AAA*_*ddd 7

请注意,自从我写这篇文章以来,问题已经改变了

如果您查看源代码

if( startIndex == 0 && length == this.Length) {
   return this;
}
Run Code Online (Sandbox Code Playgroud)

所以,当你用Substring(0)你得到一个引用的原话变异与它unsafe

在第二个示例Substring(1)中,分配一个string


更深入的分析。

string x = "shark";
string y = x.Substring(0);
// x reference and y reference are pointing to the same place

// then you mutate the one memory
c[4] = 'p';

// second scope
string x = "shark";
string y = x.Substring(1);
// x reference and y reference are differnt

// you are mutating y
c[0] = 'p';
Run Code Online (Sandbox Code Playgroud)

编辑

stringinterened,并且编译器认为任何文字"shark"是相同的(通过散列)。这就是为什么第二部分即使具有不同的变量也会产生变异结果的原因

字符串实习是指通过.NET公共语言运行库(CLR)中的哈希表在字符串实习生池中具有每个唯一字符串的单个副本。其中键是字符串的哈希,值是对实际String对象的引用

调试第二部分(无范围或无范围以及不同的变量)

在此处输入图片说明

编辑2

范围对我或框架或核心无关紧要,它总是产生相同的结果(第一个结果),它很可能是实现细节,并且规范中实习的定义不明确


hov*_*jan 0

编译按函数进行,这就是为什么在第一种情况下,如果您将字符串放入一个范围编译器一次检查字符串并Intern Pool仅放入一个字符串,当您在内存中更改时,所有硬编码字符串都会更改。

在第二种情况下,当我将字符串放入不同的函数中时,编译器仅为第一个函数添加字符串,并且当我们使用不安全代码更改字符串时,在编译器转到第二种方法并尝试查找字符串但在编译器中找不到该字符串后,它会Intern Pool对该字符串应用更改那种字符串(因为我们已经将其更改为),这就是为什么它添加新字符串并且输出变得不同。sharkInterned Poolsharp