3

鉴于:

        object literal1 = "abc";
        object literal2 = "abc";

        object copiedVariable = string.Copy((string)literal1);

        if (literal1 == literal2)
            Console.WriteLine("objects are equal because of interning");//Are equal

        if(literal1 == copiedVariable)
            Console.WriteLine("copy is equal");
        else
            Console.WriteLine("copy not eq");//NOT equal

这些结果意味着copiedVariable不受字符串实习的影响。为什么?

在这种情况下,有没有被实习的等效字符串是有用的,或者这种行为是由于某些语言细节造成的?

4

2 回答 2

5

如果您考虑一下,字符串的实习是它在编译时在文字上触发的过程。这意味着:

  • 当您将文字分配/绑定到变量时,它是隐式的
  • 复制引用时它是隐式的(即字符串 a = some_other_string_variable;)

另一方面,如果您手动创建字符串的实例- 在运行时使用 StringBuilder 或通过 Copy-ing,则您必须通过调用String 类的Intern方法专门请求对其进行实习。

即使在文档的备注部分中也指出:

公共语言运行时通过维护一个称为实习池的表来保存字符串存储,该表包含对程序中以编程方式声明或创建的每个唯一文字字符串的单个引用。因此,具有特定值的文字字符串的实例在系统中仅存在一次。例如,如果您将相同的文字字符串分配给多个变量,则运行时会从实习池中检索对文字字符串的相同引用并将其分配给每个变量。

String 类的Copy方法的文档指出:

创建一个新的 String 实例,其值与指定的 String 相同。

这意味着它不会只返回对同一字符串的引用(来自实习生池)。再说一次,如果它这样做了,那么它就没有多大用处了,会有吗?!

于 2013-03-01T15:30:31.810 回答
1

某些语言要求结果是某些方法/程序的副本。

例如在substring类型方法中。即使您调用foo.substring(0, foo.length)(以及您可能如何实现stringcopy),语义也会相同。

注意:IIRC*,但.NET 的实现并非如此string.Substring。从MSDN也不是很清楚。(见下文)

它返回:

一个字符串,它等效于在此实例中从 startIndex 开始的长度为 length 的子字符串,如果 startIndex 等于此实例的长度且长度为零,则为 Empty。

它指出:

此方法不会修改当前实例的值。相反,它返回一个新字符串,其长度字符从当前字符串中的 startIndex 位置开始。

更新

我没记错,它确实会检查string InternalSubString(int startIndex, int length, bool fAlwaysCopy)if fAlwaysCopyis not falseSubstring传递false给这个方法。

更新 2

看起来string.Copy可以使用InternalSubString并传递true给上述参数,但是从反汇编来看,它似乎使用了稍微优化的版本,并且可能节省了方法调用。

对不起,多余的信息。

* 我记得的原因是在实施substringIronScheme 的过程时,R6RS 规范要求制作一个副本 :)

于 2013-03-01T15:36:13.273 回答