代码之家  ›  专栏  ›  技术社区  ›  foson

为什么.NET创建新的子字符串而不是指向现有的字符串?

  •  7
  • foson  · 技术社区  · 15 年前

    从使用反射镜的简单外观来看,它看起来像 String.Substring() 为每个子串分配内存。我说的对吗?我认为这不是必要的,因为弦是不变的。

    我的基本目标是创建一个 IEnumerable<string> Split(this String, Char) 不分配额外内存的扩展方法。

    5 回复  |  直到 15 年前
        1
  •  22
  •   SingleNegationElimination    15 年前

    大多数具有不可变字符串的语言创建新子字符串而不是引用现有字符串的一个原因是,这会干扰以后垃圾收集这些字符串。

    如果字符串用于其子字符串,但较大的字符串无法访问(通过子字符串除外),会发生什么情况?较大的字符串将无法收集,因为这将使子字符串无效。从长远来看,在短期内保存内存似乎是一种好方法,但从长远来看,这将成为内存泄漏。

        2
  •  2
  •   Spence    15 年前

    不使用字符串类在.NET内部进行搜索是不可能的。您必须传递对可变数组的引用,并确保没有人出错。

    .NET将在每次请求时创建一个新字符串。唯一的例外是由编译器创建的内部字符串(可以由您完成),它被放入内存中一次,然后由于内存和性能的原因,指针被建立到字符串上。

        3
  •  1
  •   Guffa    15 年前

    每个字符串都必须有自己的字符串数据,字符串类的实现方式是这样的。

    您可以使用字符串的一部分创建自己的子字符串结构:

    public struct SubString {
    
       private string _str;
       private int _offset, _len;
    
       public SubString(string str, int offset, int len) {
          _str = str;
          _offset = offset;
          _len = len;
       }
    
       public int Length { get { return _len; } }
    
       public char this[int index] {
          get {
             if (index < 0 || index > len) throw new IndexOutOfRangeException();
             return _str[_offset + index];
          }
       }
    
       public void WriteToStringBuilder(StringBuilder s) {
          s.Write(_str, _offset, _len);
       }
    
       public override string ToString() {
          return _str.Substring(_offset, _len);
       }
    
    }
    

    您可以使用其他方法(如比较)充实它,这也可以在不提取字符串的情况下完成。

        4
  •  0
  •   Philippe Leybaert    15 年前

    因为字符串在.NET中是不可变的,所以每个产生新字符串对象的字符串操作都将为字符串内容分配一个新的内存块。

    理论上,在提取子字符串时可以重用内存,但这会使垃圾收集非常复杂:如果原始字符串是垃圾收集的呢?共享其中一部分的子字符串会发生什么情况?

    当然,没有什么能阻止.NET BCL团队在将来的.NET版本中更改这种行为。它不会对现有代码产生任何影响。

        5
  •  0
  •   Babak Naffas    15 年前

    添加到字符串是不可变的这一点上,应该是下面的代码段将在内存中生成多个字符串实例。

    String s1 = "Hello", s2 = ", ", s3 = "World!";
    String res = s1 + s2 + s3;
    

    s1+s2=>新建字符串实例(temp1)

    temp1+s3=>新字符串实例(temp2)

    res是对temp2的引用。