C# – 字符串实际上是一个字符数组还是只有一个索引器?

由于在C#中可以使用以下代码,因此我认为string是否实际上是一个chars数组:

string a="TEST"; char C=a[0]; // will be T 

System.String不是Char的.NET数组,因为这样:

 char[] testArray = "test".ToCharArray(); testArray[0] = 'T'; 

将编译,但这:

 string testString = "test"; testString[0] = 'T'; 

将不会。 字符串数组是可变的,字符串不是。 另外, string is Array返回false,而char[] is Array返回true。

不,这不是arrays。 但它确实有一个索引器。 两全其美。

.NET中的字符串由System.String类支持,该类在内部使用一堆不安全的方法,使用标准的C内存操作技术对实际的字符串数据进行指针操作。

String类本身不包含数组,但它有一个indexer属性,允许您将数据视为数组。

不,String是.Net中的一个类。 它可能由数组支持。 但它不是一个数组。 类可以有索引器,这就是String正在做的事情。

请参阅有关此声明的详细说明:根据我的理解,所有字符串都存储在一个公共blob中。 因此,“foo”和“foo”指向该blob中的相同点…字符串在C#中不可变的原因之一。

string不是char[] ,尽管它有一个.ToCharArray() 。 它还有一个索引器,它允许你单独访问字符,就像你已经显示的那样。 它可能是在内部使用数组实现的,但这是一个实现细节。

字符串对象包含一个连续的characers块,就像字符数组一样,但字符串对象既不是,也不包含数组对象。

编译器知道字符串字符串是不可变的,因此在访问字符串时它可以执行某些优化,其方式与访问数组时的优化方式相同。 因此,当您通过索引访问字符串时,代码可能最终直接访问字符串数据而不是调用索引器属性。

为斯科特·多尔曼和古法的答案添加一点。 如果你在字符串’abcd’上使用Windbg和!DumpObject,你会得到这样的东西。

 0:000> !do 01139b24 Name: System.String MethodTable: 79330a00 EEClass: 790ed64c Size: 26(0x1a) bytes (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll) String: abcd Fields: MT Field Offset Type VT Attr Value Name 79332c4c 4000096 4 System.Int32 1 instance 5 m_arrayLength 79332c4c 4000097 8 System.Int32 1 instance 4 m_stringLength 793316e0 4000098 c System.Char 1 instance 61 m_firstChar 79330a00 4000099 10 System.String 0 shared static Empty >> Domain:Value 00181b38:01131198 << 79331630 400009a 14 System.Char[] 0 shared static WhitespaceChars >> Domain:Value 00181b38:011318b8 << 

你会注意到它只有三个实例字段。 m_arrayLength,m_stringLength和m_firstChar。 它不包含实例System.Char []其他2个字段是静态共享的,因此每个System.String都具有相同的空字符串和WhitespaceChar字符数组。

如果您使用DumpByte,您将看到堆中的字符串数据(在本例中为abcd),当然从偏移量0x0c(m_firstChar)开始,宽度为8字节(对于unicode,m_stringLength为4 x 2)。

 0:000> db 01139b24 L1A 01139b24 00 0a 33 79 05 00 00 00-04 00 00 00 61 00 62 00 ..3y........ab 01139b34 63 00 64 00 00 00 00 00-00 00 cd..... 

如果您要查看SSCLI,您会看到它,正如Scott所说,它运行不安全的代码并使用指针技术使用m_firstChar和m_stringLength读取数据。

String是一个类,它接受一个char数组来自己初始化,所以当你尝试在某个索引处获取元素时,它返回char。 检查字符串类

 public sealed class String : IComparable, ICloneable, IConvertible, IComparable, IEnumerable, IEnumerable, IEquatable { // Summary: // Initializes a new instance of the System.String class to the value indicated // by an array of Unicode characters. // // Parameters: // value: // An array of Unicode characters. [SecuritySafeCritical] public String(char[] value); } 

另请参见String类声明。

 public sealed class String : IComparable, ICloneable, IConvertible, IComparable, IEnumerable, IEnumerable, IEquatable 

哪个由IEnumerableinheritance。

在字符串类中有一个get属性,它在传递索引时返回char,请参见图像。 这清楚地说明了在当前System.String中的指定位置获取System.Char对象

 public char this[int index] { get; } 

在将stringstring不是char数组。 该表示法仅用于访问字符串中不同位置(索引)的字符。

使用Reflector ,我们可以看到字符串确实实现了IEnumerable 。 所以,它不是一个字符数组,但实质上可以像一个一样使用。

 public sealed class String : IComparable, ICloneable, IConvertible, IComparable, IEnumerable, IEnumerable, IEquatable 

编辑:

实现IEnumerable并不意味着该类型将被索引。 我并不是故意要传达这一点。 这意味着您可以枚举它并像集合一样使用它。 我想说的更好的方法是字符串不是字符数组,而是字符集合。 感谢您的评论。

字符串根本不是数组,因为"Hello" is char[]被评估为false

每个人都给出了一半的答案,所以这里有两个部分:

1)严格来说,是的,.NET中的String是一个字符数组。 它的内部实现和数组的语义定义都是如此。

2)然而,正如其他人所指出的那样,弦乐有点奇怪。 它不是所有其他数组的System.Array。 因此,在严格的.NET特定方式中,String不是数组。