Для этого нет действительного «ожидаемого» результата; поведение совершенно не определено; происходит то, что вы присваиваете строковую ссылку на S
(что, очевидно, также C
), затем лежит и говорите с кодом индексатора массива, но выполняете против экземпляра строки. Поскольку это интернированный "Hello"
, вы перезаписываете глобальный интернированный "Hello"
, но: код операции индексатора массива знает только, как общаться с массивами, и, таким образом, получает неправильное смещение . Внутреннее расположение строки и массива может быть разным (и, разумеется, в зависимости от времени выполнения, версии фреймворка и т. Д.), Поэтому оно может (и явно делает) обновлять байты, начиная с неправильного смещения от заголовка объекта.
Что касается того, почему работает на некоторых установках: опять же, неопределенное поведение. Неопределенное поведение разрешено «работать», где важны воздушные кавычки.
Если вы хотите правильно получить смещения, тогда либо используйте fixed
, либо ToSpan()
/ ToMemory()
. Первый позволяет трактовать string
как char*
; вторая позволяет рассматривать string
как ReadOnlySpan<char>
(но вы можете использовать MemoryMarshal
, чтобы повысить ReadOnlyMemory<char>
до Memory<char>
).
Примеры:
Console.WriteLine("Hello"); // Hello
// note: using MemoryMarshal.* is like using Unsafe.*; you
// are explicitly accepting the consequences if used incorrectly
var span = MemoryMarshal.AsMemory("Hello".AsMemory()).Span;
span[0] = 'W';
span[1] = 'o';
span[2] = 'r';
span[3] = 'l';
span[4] = 'd';
Console.WriteLine("Hello"); // World
// ditto, "unsafe" means you're accepting the consequences
fixed(char* c = "Hello")
{
c[0] = 'd';
c[1] = 'l';
c[2] = 'r';
c[3] = 'o';
c[4] = 'W';
}
Console.WriteLine("Hello"); // dlroW
Кроме того, предположительно, действительно не нужно говорить, но ... не делайте этого!