Поскольку в С# существует следующий код, я интересуюсь, является ли строка фактически массивом символов:
string a="TEST";
char C=a[0]; // will be T
Поскольку в С# существует следующий код, я интересуюсь, является ли строка фактически массивом символов:
string a="TEST";
char C=a[0]; // will be T
System.String не является .NET-массивом Char, потому что это:
char[] testArray = "test".ToCharArray();
testArray[0] = 'T';
будет компилироваться, но это:
string testString = "test";
testString[0] = 'T';
не будет. Char массивы изменяемы, строки - нет. Кроме того, string is Array
возвращает false, а char[] is Array
возвращает true.
Нет, это не массив. Но у него есть указатель. Лучшее из обоих миров.
Строки в .NET поддерживаются классом System.String
, который внутренне использует кучу небезопасных методов для манипуляции указателями по фактическим строковым данным с использованием стандартных методов манипуляции с памятью.
Сам класс String
не содержит массив, но имеет свойство индексатора, которое позволяет обрабатывать данные так, как если бы они были массивом.
Нет, String - это класс в .Net. Он может поддерживаться массивом. но это не массив. Классы могут иметь указатели, и это то, что делает строка.
См. комментарии для разработки этого утверждения: Из того, что я понимаю, все строки хранятся в общем блобе. Из-за этого "foo" и "foo" указывают на ту же самую точку в этом блоке... одна из причин, по которой строки являются неизменными в С#.
A string
не является char[]
, хотя он имеет .ToCharArray()
. Также у него есть индекс, который позволяет вам обращаться к персонажам индивидуально, как вы показали. Вполне вероятно, что он был реализован с массивом внутри, но это деталь реализации.
Строковый объект содержит непрерывный блок символов, подобно массиву символов, но строковый объект не является и не содержит объект массива.
Компилятор знает, что строковая строка неизменна, поэтому она может делать определенные оптимизации при доступе к строке, так же, как она делает оптимизацию при доступе к массиву. Таким образом, при доступе к строке по индексу, вероятно, что код в конечном итоге обращается к строковым данным напрямую, а не к вызову свойства индексатора.
Чтобы добавить немного к Скотту Дорману и Гуфе, ответьте. Если вы используете Windbg и! DumpObject в строке 'abcd', вы получите что-то вроде этого.
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 Char Array.
Если вы выполните это с помощью DumpByte, вы увидите строковые данные (в данном случае abcd), которые в куче, которая, конечно, начинается со смещения 0x0c (m_firstChar) и имеет ширину 8 байтов (m_stringLength 4 x 2 для unicode),
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, вы увидите, что, как говорит Скотт, он запускает небезопасный код и использует методы указателей для чтения данных с помощью m_firstChar и m_stringLength.
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>
.
Внутри класса string есть свойство get, которое возвращает char при передаче индекса, см. изображение. Что явно говорит, что получает объект System.Char в указанной позиции в текущей System.String
public char this[int index] { get; }
A string
не является массивом char
, пока вы не преобразуете его в один. Обозначение просто используется для доступа к символам в разных позициях (индексах) в строке.
Используя Reflector, мы видим, что строка реализует IEnumerable<char>
. Таким образом, это не массив символов, но по существу может быть использован как один.
public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
EDIT:
Реализация IEnumerable<char>
не означает, что тип будет проиндексирован. Я не хотел этого. Это означает, что вы можете перечислить его и использовать как коллекцию. Лучший способ формулировки я хотел сказать, что строка не является символьным массивом, а представляет собой набор символов. Спасибо за комментарий.
Строки - это просто не массив, в том смысле, что "Hello" is char[]
оценивается как false
.
Каждый дал половину ответа, так что вот обе части:
1) Строго говоря, да, String в .NET - это массив символов. Это происходит как во внутренней реализации, так и благодаря синтаксическому определению массива.
2) Однако String, как отмечали другие, несколько своеобразна. Это не System.Array, как все остальные массивы. Таким образом, в строгом, специфичном .NET способе, String не является массивом.