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

时间:2010-09-08 15:14:02

标签: c# arrays string

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

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

12 个答案:

答案 0 :(得分:18)

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。

答案 1 :(得分:14)

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

答案 2 :(得分:5)

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

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:2)

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

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

为斯科特·多尔曼和古法的回答添加一些内容。如果你在字符串'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........a.b.
01139b34  63 00 64 00 00 00 00 00-00 00                    c.d......

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

答案 7 :(得分:2)

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

public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
    {
        // 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<string>, IEnumerable<char>, IEnumerable, IEquatable<string>

IEnumerable<char>继承。

在字符串类中有一个get属性,它在传递索引时返回char,请参阅图像。这清楚地说明了在当前System.String

中的指定位置获取System.Char对象
public char this[int index] { get; }

答案 8 :(得分:1)

string不是char的数组,除非您将其转换为1。该表示法仅用于访问字符串中不同位置(索引)的字符。

答案 9 :(得分:1)

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

public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>

修改

实施IEnumerable<char>并不意味着该类型将被编入索引。我不是故意转达那个。这意味着您可以枚举它并像集合一样使用它。我想说的更好的方法是字符串不是字符数组,而是字符集合。感谢您的评论。

答案 10 :(得分:1)

"Hello" is char[]评估为false的意义上,字符串不是数组。

答案 11 :(得分:0)

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

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

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