Использование кода UnSafe для перемещения указателя к следующему элементу для пользовательского класса

Можно ли сделать что-то вроде следующего на С#?

unsafe string GetName()
{
    Foo[] foo = new Foo[2]; // Create an array of Foo and add two Foo elements
    foo[0] = new Foo { Name = "Bob" };
    foo[1] = new Foo { Name = "Jane" };

    Foo *ptr = &foo;    // Get address of the first element in the array
    ptr++;  // Move to the next element in the array

    return *ptr.Name;  // Expect Name to be "Jane"
}

Я играю с пользовательскими структурами данных, и я хотел бы иметь возможность это сделать.

Я знаю, что вы можете сделать это с типами int и т. д., но как насчет определяемых пользователем структур и классов?


person user1515024    schedule 24.01.2014    source источник


Ответы (1)


Вы можете сделать это, но только если Foo является структурой, в которой все поля являются "неуправляемыми типами". int — неуправляемый тип; string нет. Вы должны использовать оператор fixed, чтобы зафиксировать массив на месте, чтобы сборщик мусора не перемещал его. Обратитесь к главе 18 спецификации и обратите внимание, что когда вы выключаете систему безопасности, она отключается. Это означает, что вы должны понимать все об управлении памятью в C#, когда пишете небезопасный код. Вы все понимаете в управлении памятью? Если ответ «нет», делайте то, что делаю я: не пишите небезопасный код. Я пишу код на C# уже десять лет, и мне еще не приходилось писать небезопасный код (кроме тестов компилятора).

Вы просто не должны делать это в первую очередь. Нет необходимости использовать небезопасный код. Если вам нужно что-то, что действует как указатель на середину массива, вы можете сделать это безопасным способом без использования указателей.

Здесь я даже написал код для вас:

http://blogs.msdn.com/b/ericlippert/archive/2011/03/10/references-and-pointers-part-two.aspx

person Eric Lippert    schedule 24.01.2014
comment
Эй, спасибо за ваш краткий ответ! Я определенно не претендую на то, что знаю больше, чем модель памяти высокого уровня для C #, я в основном просто делаю это для удовольствия. Приведенный выше код никогда не будет использоваться для производства, я просто пытаюсь создать общую потокобезопасную структуру, которая даже быстрее, чем, например, однопоточная хеш-таблица. Что еще более важно, я учу себя некоторым низкоуровневым техникам, которых, боюсь, мне сейчас не хватает. Я прочитаю первую и вторую части вашей записи в блоге, ура. - person user1515024; 24.01.2014
comment
@ user1515024: Это хорошее упражнение для обучения. Это также даст возможность изучить модель памяти C#, которая намного слабее модели памяти x86. Вы также, вероятно, обнаружите, что дженерики и указатели плохо сочетаются в C#. - person Eric Lippert; 24.01.2014
comment
Я поигрался с вашим кодом ArrayPtr‹T›, он довольно прикольный, мне нравится. Но у меня есть один вопрос, почему это структура, а не класс? Если я хочу использовать это на большом массиве, вызовет ли это проблему (или исходный массив находится в куче)? Я вижу, вы создали структуру в функциональном шаблоне, я полагаю, это для безопасности потоков? В вашем ArrayPtr, каковы плюсы структуры над классом? Я ни разу не использовал структуру (или не видел ее) в производственном коде, возможно, я плохо информирован? Заранее спасибо. - person user1515024; 25.01.2014
comment
@ user1515024: У вас пять вопросов, а не один. Во-первых: я сделал его структурой, потому что это тип значения, потому что он (1) очень мал и (2) логически является значением. - person Eric Lippert; 25.01.2014
comment
@ user1515024: Во-вторых: все массивы находятся в куче в C#. Массивы являются ссылочными типами, а не типами значений, потому что они (1) большие и (2) не ведут себя как значения. - person Eric Lippert; 25.01.2014
comment
@user1515024: user1515024: Третье: нет, меня ни на йоту не волнует безопасность потоков. Вы всегда должны делать типы значений неизменяемыми, потому что изменяемые типы значений — это наихудшая практика в C#. Подумайте об этом так: когда вы добавляете 1 к 2, вы не превращаете 2 в 3. 2 остается прежним. Результатом добавления является новая вещь. Если бы 2 могло волшебным образом превратиться в 3, это было бы запутанно. Значения всегда следует рассматривать как значения, а не как переменные. Рассматривайте переменные как переменные. - person Eric Lippert; 25.01.2014
comment
@ user1515024: В-четвертых: это часто задаваемый вопрос на этом сайте. Поищи это. - person Eric Lippert; 25.01.2014
comment
@user1515024 user1515024: В-пятых: многие разработчики C# очень плохо осведомлены о семантике типов значений. Я много писал на эту тему. Это было бы хорошим местом для начала: blogs.msdn.com/ b/ericlippert/archive/tags/value+types -- начать снизу, в обратном хронологическом порядке. - person Eric Lippert; 25.01.2014
comment
Спасибо за ответы на все вопросы, пять по цене одного! - person user1515024; 25.01.2014