string是引用类型(类似于object).为什么在以下场景中的diff行为 - 在创建字符串和对象的实例时?
我理解字符串中不变性等的概念,但这与分配给字符串的值(不会改变)有关.我的问题更多的是为什么s2正在创建另一个完整的实例,而如果我已经完成了对象它不会这样做?

字符串示例
class Program
{
static void Main(string[] args)
{
string s1 = "Hello";
string s2 = s1;
s1 = null;
Console.WriteLine("s1 = " + s1);
Console.WriteLine("s2 = " + s2);
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:s2仍然打印"你好"
对象的例子
class Program
{
static void Main(string[] args)
{
Name s1 = new Name();
s1.id = 5;
Name s2 = s1;
s1 = null;
Console.WriteLine("s1 = " + s1.id);
Console.WriteLine("s2 = " + s2.id);
Console.ReadLine();
}
}
public class Name
{
public int id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
输出:s1和s2都为空;
在你的第二个代码片段,s2是不为空,但你不能看到它,因为s1.id罚球NullReferenceException和你没有处理 it.So程序永远不会到达第二line.Remove它,你会看到5在Console.之后 s1 = null;,s2不改变它仍然将s1's 旧位置指向内存.
此外,如果您不想删除第一行,也可以将其放在try/catch 块内:
try
{
Console.WriteLine("s1 = " + s1.id);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("s2 = " + s2.id);
Run Code Online (Sandbox Code Playgroud)
你可以5在Console和异常消息中看到.但这完全没必要; 它肯定会抛出异常,因为它s1是null.因此,除了之外,其他引用类型之间没有区别stringimmutability
首先,我确信你会意识到你将获得很多NullReferenceException你所拥有的代码.其次,字符串类是一个有趣和特殊的object,您可以在心理上将其视为primitive数据类型.我只想说,System.String 它不是一种原始类型 ......但你可以把它想象成一般用途.
我已经绘制了一些图表,可以更好地显示您给出的每个示例中发生的事情.
当你
string s1 = "Hello";
string s2 = s1;
Run Code Online (Sandbox Code Playgroud)
创建一个名为s1的string类型的对象,该对象指向保存该值的内存空间"Hello".然后创建一个名为s2的字符串类型的新对象,并将"Hello"s1 的值复制到另一个内存空间并通过其寻址s2.这会使你的记忆看起来像下面那样.

现在,当你
s1 = null;
Run Code Online (Sandbox Code Playgroud)
你已经设置了s1指向的引用null pointer,它使得带有"Hello"值的内存浮动,直到垃圾收集器到来并将其删除.此时s1仍然指向先前复制的值.

现在让我们看一下它与普通对象的区别.
当你
Name s1 = new Name();
s1.id = 5;
Name s2 = s1;
Run Code Online (Sandbox Code Playgroud)
s1创建一个调用的内存空间,它指向内存中新分配的空间,该空间足以容纳Name对象的内存.
然后你指出了所处理的内存空间s1并将其属性id调整为5.
然后你创建了一个新的内存空间s2,它将地址的值复制到上面提到的分配的内存中.所以,现在s1并s2指向内存中的同一个对象.这会使你的记忆看起来像下面那样.

注:在这一点,如果你要改变的值id,将两个改变s1和s2,如果这是可空类型你使用id,你将其设置为null,该变化将在这两个反映s1和s2.
现在,如果你去
s1 = null;
Run Code Online (Sandbox Code Playgroud)
正如你在帖子中所做的那样.s1将其地址更改为指向null pointer,s2并将继续查看内存中的相同空间.这导致您在下面看到的内容.

编辑:进一步解释为什么字符串看起来像基元而不是对象.我不知道,不过我会推测.我的猜测是它是这样设计的,因为开发人员想要使用string它就像是一个原始的.我会说,不必担心对我的字符串的杂散引用,或者clone在我对其进行更改之前不得不这样做.但是,string由于字符串很大,Microsoft无法生成基本类型.a的最大长度是a string的最大值Int32.而每一个字母是一个char这是一个Int16,所以这是某处大约2场演出,我相信(不要引用我的数学).这意味着字符串太大而无法存储在堆栈上,只有1MB.因此,字符串必须是对象并放在堆上.
如果您不知道堆栈和堆之间的差异,我建议查找它,知道如何处理内存是很好的,而在C#中,如果您决定转移到某些东西,那么所有脏工作都会为您完成像C++一样,你会发现自己管理它(不是非常有趣).
所以简而言之,我认为这是因为我们想要使用像基元这样的字符串,但由于堆栈的限制,它们被实现为对象.
| 归档时间: |
|
| 查看次数: |
211 次 |
| 最近记录: |