Как получить указатель на середину массива в C#
Во-первых, основная информация о нашей среде: мы используем C# .net 4.0, на Win7-x64, для 32-битной.
У нас есть предварительно выделенный массив -large-. В функции мы хотели бы вернуть указатель на произвольную точку в этом массиве, чтобы вызывающая функция могла знать, куда писать. Пример:
class SomeClass {
void function_that_uses_the_array() {
Byte [] whereToWrite = getEmptyPtrLocation(1200);
Array.Copy(sourceArray, whereToWrite, ...);
}
}
class DataProvider {
int MAX_SIZE = 1024*1024*64;
Byte [] dataArray = new Byte[MAX_SIZE];
int emptyPtr=0;
Byte[] getEmptyPtrLocation(int requestedBytes) {
int ref = emptyPtr;
emptyPtr += requestedBytes;
return dataArray[ref];
}
}
По сути, мы хотим предварительно выделить большой кусок памяти и зарезервировать части этого блока памяти произвольной длины и позволить некоторым другим классам / функциям использовать эту часть памяти.
В приведенном выше примере функция getEmptyPtrLocation является неправильной; он объявляется как возвращающий Byte[], но пытающийся вернуть одно байтовое значение.
Спасибо
5 ответов
Как уже говорили другие, вы не можете делать это в C# - и вообще вы не должны делать ничего подобного. Работайте с системой - воспользуйтесь сборщиком мусора и т. Д.
Сказав это, если вы хотите сделать что-то подобное, и вы можете доверять своим клиентам не превышать выделенный им слот, вы можете вернуть свой метод ArraySegment<byte>
вместо byte[]
, Это будет представлять "часть массива". Очевидно, что большинство методов в.NET не используют ArraySegment<T>
- но вы могли бы потенциально написать методы расширения, используя его в качестве цели для некоторых из наиболее распространенных операций, которые вы хотите использовать.
Это C#, а не C++ - вы действительно работаете против сборщика мусора. Распределение памяти, как правило, очень быстрое в C#, и оно не страдает от фрагментации памяти, что является одной из других основных причин предварительного выделения в C++.
Сказав это, и вы все еще хотите сделать это, я бы просто использовал индекс и длину массива, так что вы можете использовать Array.Copy
написать в этой позиции.
Редактировать:
Как уже отмечали другие ArraySegment<T>
лучше соответствует вашим потребностям: он ограничивает потребителя только его частью массива, и ему не требуется выделять отдельный массив перед обновлением содержимого в исходном массиве (как представлено ArraySegment).
Довольно старый пост, но у меня есть простое решение. Я вижу, что у этого вопроса есть много ответов типа "ты не должен". Если есть способ что-то сделать, почему бы не использовать его?
Но кроме этого, вы можете использовать следующее
int[] array = new int[1337];
position = 69;
void* pointer = (void*)Marshal.UnsafeAddrOfPinnedArrayElement(array, position);
Не вдаваясь в неуправляемый код, вы не можете вернуть указатель на середину массива в C#, все, что вы можете сделать, это вернуть индекс массива, в который вы хотите ввести данные.
Если вы должны сделать это, ваши варианты включают возвращение ArraySegment (как указал Джон Скит) или использование Streams. Вы можете вернуть MemoryStream, который является подмножеством массива, используя этот конструктор. Однако вам нужно будет обрабатывать все операции чтения и записи в памяти как потоковые операции, а не как операции смещения.