【问题标题】:Is List<T> a pointer?List<T> 是指针吗?
【发布时间】:2011-12-10 02:55:54
【问题描述】:

我注意到List&lt;T&gt; 的行为不同于其他简单对象,例如String。这个问题似乎是新手,但这真的让我很震惊,因为我认为List&lt;T&gt; 是简单的对象。

以下面的代码为例:

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

最后,ls1 将等于 {"a", "b"}ls2。这与这段代码的行为确实不同:

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

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

也就是说List&lt;T&gt;实际上是一个指针,对吧?

【问题讨论】:

  • 它们被称为引用,而不是指针!
  • List&lt;T&gt; 是一个对象,所以是的,它“就像一个指针”(我使用这个术语很宽松,因为托管代码中的对象不称为“指针”,它们被称为引用)。
  • List 和 String 在这方面是相同的。您得到不同结果的唯一原因是您在这些 sn-ps 中做了不同的事情。对比List&lt;String&gt; ls1 = new List&lt;String&gt;(); ls1.Add("a"); ls2 = ls1; ls2 = new List&lt;String&gt;(); ls2.Add("b"),更接近。或者为了更清楚地说明这与您的字符串 sn-p 的相同之处,请替换集合初始值设定项:List&lt;String&gt; ls1 = new List&lt;String&gt; {"a"}; List&lt;String&gt; ls2 = ls1; ls2 = new List&lt;String&gt; {"b"};.
  • 这到底是怎么得到这么多赞成票的?这不是一个有趣的问题,只是对作业如何工作的误解。
  • @R0MANARMY:为我的问题辩护,我想说投票不是为了“有趣”的问题,而是为了“有用且清晰” 问题。我确实做了一些研究,但没有发现任何结论,因为我的 reference 术语有误。对不起,我的新手问题冒犯了你。 :)

标签: c# list pointers


【解决方案1】:

List&lt;T&gt;一个引用类型,所以是的,它的行为就像一个指针。

String 也是一种引用类型,但字符串是不可变的,并且在某些情况下它们的行为类似于 值类型(与引用类型相反),因此您在这里感到困惑。

这里有一个很好的解释为什么字符串会这样工作:In C#, why is String a reference type that behaves like a value type?

【讨论】:

    【解决方案2】:

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

    ls1 引用的List&lt;string&gt; 对象的更改通过对该对象的所有引用可见,包括ls2。当您制作ls2 = ls1 时,您基本上是在说ls1ls2 都指的是同一个对象。通过引用变量ls1 对对象的更改可以通过引用变量ls2 看到。

    【讨论】:

    • The line s1 = "b" actually assigns a new reference to - 我相信它分配了一个新值而不是参考
    • @sll,它分配一个对新字符串的引用,您可以从变量的角度考虑一个值,因为字符串是在 GC 堆上管理的引用类型。请参阅 (yoda.arachsys.com/csharp/strings.html) 以获得很好的解释。
    • 嗯,它为变量分配了一个新值,尽管该值是一个引用(因为引用类型的变量存储引用)。
    【解决方案3】:

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

    【讨论】:

    • 需要注意的是,C# 也可以通过unsafe 代码与指针通信,因此指针和引用之间的另一个区别。
    • @MarcGravell 同一个词可以有两个不同的概念。在 C++/Cli 中,您有托管指针和指针。但它们都被命名为“指针”。并不是 C# 支持不安全编码使引用成为“引用”
    【解决方案4】:

    C# 中的每个对象都是一个引用。 int、string、char 等原语不是引用。

    【讨论】:

    • 它不是“原始”,它不是引用类型,而是值类型——包括structs。
    • 我认为将它们称为对象会令人困惑。值类型也继承自 object。还有一些类型不是原始类型,而是值类型,比如Guid
    • 另外,“C# 中的每个对象都是一个引用”......嗯,不是真的 - 一个对象就是一个对象; reference 是对对象的...(单词的草稿)reference,可以在堆栈的工作部分,也可以在字段/本地。跨度>
    • 当然IntPtr是一个值类型一个原语(检查.IsPrimitive),并且是一个指针(与,但不同于参考)...有点有趣
    【解决方案5】:

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

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

    当 s2 被初始化时,s1 的值被复制到分配给 s2 的空间中。因此,如果您正在窥探内存,您可以在内存中的 两个 不同位置(分配给 s1 的位置和分配给 s2 的内存)找到“a”的十六进制表示。但是,如果您尝试对引用类型(例如 List)做同样的事情,那么当您说这样的事情是通过引用传递时会发生什么:

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

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

    【讨论】:

    • 字符串不是值类型。它的行为类似于值类型,但它是不可变的引用类型。
    猜你喜欢
    • 2021-06-11
    • 2023-03-05
    • 2016-11-23
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 2023-04-01
    • 1970-01-01
    • 2021-03-12
    相关资源
    最近更新 更多