String.IsInterned的目的是什么?

17
String类中有一个方法IsInterned()。我从未使用过这个方法,请帮我理解如何最好地使用它。

2
不满意微软官方文档?请访问http://msdn.microsoft.com/en-us/library/system.string.isinterned.aspx。 - tzup
5
文档说明函数的作用,但并未说明什么情况下会使用该函数。 - Gabe
3个回答

13
考虑到字符串驻留是一种优化,它在增加某些良好的特性的同时,换取了其他一些良好特性的减少。具体来说,字符串驻留具有以下优点:
  1. 不会浪费内存在重复的字符串上。
  2. 对于已知都驻留的字符串之间的相等比较非常快速。
  3. 与已驻留的字符串进行相等比较仍然比如果它们未被驻留要快得多。
  4. 在某些情况下,其他比较会获得性能提升。

它还具有以下缺点:

  1. 字符串不会被垃圾回收机制频繁回收(如果有的话),因此用于永远不再被使用或者很长时间不再被使用的字符串的内存就无法被回收(如果将所有字符串都驻留,你最终可能会面临非常糟糕的内存使用情况)。

作为一种优化,我们在以下情况下使用字符串驻留:要么优点超过缺点,要么缺点不成立(如果我们知道该字符串在应用程序生命周期内将一直存在,或者知道它将被多次使用,则缺点不成立)。

同样地,我们不会在坏的品质超过好的品质的情况下使用它。(大部分时间是这样的)

IsInterned()方法可用于找到中间点。

考虑我有一个字符串属性Name:

public string Name { get; set; }

假设我知道按给定的Name查找对象很常见,或尝试查找具有相同Name的对象或对其进行许多等式比较。或者我知道将会有许多其他具有相同Name的对象。或两者兼而有之。

在这些情况下,我可能考虑使用内部化技术:

private string _name;
public string Name
{
  get { return _name; }
  set { _name = string.Intern(value); }
}

当然,这是否是一个好主意取决于实习的优点和缺点。

在使用和不使用之间存在可能性:

private string _name;
public string Name
{
  get { return _name; }
  set { _name = string.IsInterned(value) ?? value; }
}

如果字符串 value 已经被内部化(interned),那么我们就已经避免了内部化的缺点,不会再受到影响,因此我们可以利用它。但是如果 value 没有被内部化,那么我们就直接使用它。

这也是一种优化方法,针对不同的情况进行优化。只有当一定数量的值可能由其他代码内部化(或者因为它们与汇编中的字面量匹配)时,才会受益于这种优化。否则,这只会浪费时间进行查找。它可能比 Intern() 更少使用,而后者又比仅使用字符串而忽略内部化更少使用,但这确实展示出了一种它有用的时候。


请注意,IsInterned在某些情况下可能会返回一个值,而你(在我学习之前)可能没有预料到。简而言之,编译器可以根据应用程序代码中字符串的使用情况来优化内部池中的某些值。 - ruffin

3

如果您想锁定字符串值,其中一个可能的用途是使用它。

接下来的内容如下:

string s = //get it from somewhere, e.g. a web request
lock (s){
//do something
}

存在一个问题,因为可能会有两个不同的请求获取相同的字符串,但它们都进入了受保护的代码。这是因为可能有两个不同的字符串对象具有相同的值。

然而,有一个称为intern池的东西,它是一个包含某些字符串的单个实例的表(例如,所有文字都在其中)。

您可以使用它来使锁定起作用:

string s = //get it from somewhere, e.g. a web request
lock (string.Intern(s)){
//do something
}

这个函数将返回一个字符串池中与s相同值的字符串引用,因此可以安全锁定。

IsIntern函数仅检查您所持有的引用是否是指向字符串池中的字符串的引用。


9
永远不要对字符串进行锁定。 字符串具有域敏捷性,即相同的字符串实例可能会从多个应用程序域访问,特别是在被interned(内部化)时。结果可能是一个线程正在等待在一个不相关的应用程序域中释放锁定……非常令人讨厌的影响。 - MaLio
在字符串.Intern上进行锁定将会合并锁! - usr

0

C# 中的字符串字面量是被池化(即它们被存储到一个内部池中),因此每个字面量的出现只有一个实例。如果您正在创建自己的语言(例如某些脚本系统),则可以使用 IsInterned 和 Intern 来产生相同的效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接