List 是指针吗?

我注意到List的行为与其他简单对象不同,例如String 。 这个问题看似新手,但这真让我感到震惊,因为我认为List是简单的对象。

以下面的代码为例:

 List ls1 = new List(); ls1.Add("a"); List ls2 = ls1; ls1.Add("b"); 

最后, ls1将等于{"a", "b"}ls2也是如此。 这与此代码的行为完全不同:

 String s1 = "a"; String s2 = s1; s1 = "b"; 

其中s1的末尾等于bs2等于a

这意味着List实际上是指针对吗?

List一个引用类型 ,所以它的行为就像一个指针。

String也是一种引用类型,但字符串是不可变的,它们的行为类似于值类型 (与引用类型形成对比),因此在这里你会感到困惑。

有一个很好的解释为什么字符串在这里工作: 在C#中,为什么String是一个行为类似值的引用类型?

s1 = "b"实际上为s1分配了新的引用。 s1s2现在指的是两个不同的对象。

ls1引用的List对象的更改通过对该对象的所有引用都可见,包括ls2 。 当你ls2 = ls1你基本上都说ls1ls2指的是同一个对象。 通过引用变量ls2可以看到通过引用变量ls1对对象的更改。

在C#中,它们被称为references ,而不是pointers 。 可能它们是相同的东西减去你不能将它们转换为整数来打印它们并减去禁止的指针算法这一事实。 从技术上讲,它们是“不透明的”,所以你不应该(不应该)知道它们是如何工作的。 显然,如果您使用托管C ++,这种不透明性会被破坏:-)

C#中的每个对象都是一个引用。 像int, string ,char这样的基元不是引用。

String,int,float都是值类型。 所以,当你说

 String s1 = "a"; String s2 = s1; s1 = "b"; 

初始化s2时,s1的值被复制到分配给s2的空间中。 所以,如果你窥探内存,你可以在内存中的两个不同位置找到“a”的hex表示(分配给s1的位置和分配给s2的内存)。 但是如果你尝试使用引用类型(如List)执行相同的操作,那么当你说这样的内容是通过引用传递时会发生什么:

 List ls1 = new List(); ls1.Add("a"); List ls2 = ls1; ls1.Add("b"); 

是有对应于堆上分配的List的对象。 找到此对象的位置的地址位于为局部变量s1和s2分配的空间,而不是驻留在该空间中的实际值。 原因是对象(List)可能是一个大对象,并且可能长期存在于程序的生命周期中,从堆栈中为这样的对象分配内存将是昂贵的。 我建议您阅读此问题主题以了解有关CLR如何真正解释值类型和引用类型的更多信息