2014-02-20 5 views
1

Я выполняю эксперимент как часть процесса R & D. Мне нужно иметь возможность устанавливать значения в структуре и извлекать их и устанавливать их как байт [].Скопируйте управляемый массив в неуправляемый массив фиксированного размера и из него

Вот моя структура:

[StructLayout(LayoutKind.Explicit, Size = 17)] 
unsafe internal struct MyBuffer 
{ 
    [FieldOffset(0)] 
    internal fixed byte Bytes[17]; 

    [FieldOffset(0)] 
    internal long L1; 

    [FieldOffset(8)] 
    internal long L2; 

    [FieldOffset(16)] 
    internal byte B; 
} 

Установка значений, очевидно, автоматически устанавливается байт []:

MyBuffer test = new MyBuffer(); 
test.L1 = 100; 
test.L2 = 200; 
test.B = 150; 

Проверка теста в режиме отладки дающий то, что я ожидал.

Что мне нужно следующий образом:

  1. Чтобы иметь возможность читать неуправляемый фиксированный массив байт в виде 17 байт длиной управляемого массива.
  2. Для установки неуправляемого массива фиксированного байта из 17-байтового управляемого массива.

ПРИМЕЧАНИЕ:

  1. Если это вообще возможно, я не хочу использовать маршалинг, как это чувствительная операция времени.
  2. Я не могу опустить фиксированную директиву, поскольку это вызывает ошибку времени выполнения из-за перекрытия объектов и не-объектов в структуре.
+0

Пожалуйста, не включайте языковой тег в заголовок, если это не имеет смысла без него. Теги служат для этой цели. –

+2

Marshaling - это требование к рок-музыке. У этого вопроса есть обычная проблема с попытками оптимизации, он не говорит, насколько быстрее он должен быть, поэтому мы не можем сказать, какой может быть наиболее подходящий ответ. –

+0

Ганс, если Маршаллинг - это твердое требование, то это ответ. Я сказал: «Если вообще возможно, я не хочу использовать сортировку». Неважно, насколько быстрее альтернатива, так как вы говорите, что альтернативы нет. – IamIC

ответ

1

Вы уже используете небезопасный код, так почему бы просто не получить указатель на структуру и передать ее? Разве это не работает?

MyBuffer bf = new MyBuffer(); 
bf.L1 = 23; 

unsafe 
{ 
    MyBuffer* pStruct = &bf; 

    YourNativeMethod(pStruct); 
} 

[DllImport] 
static extern void YourNativeMethod(MyBuffer* pStruct); 

Чтобы избежать всех маршалинг, вы, возможно, придется написать на C++/CLI обертку, я не уверен, если .NET делает сортировочных даже если вы передаете указатель небезопасным.

Вам даже не нужен байтовый массив, нативный метод, конечно, не волнует, передаете ли вы указатель на массив байтов или структуру. Все это массив байтов: D

EDIT: Поскольку ваш случай явно не вызывает метод native, мы должны обойти это.

Проблема в том, что фиксированный байт [] на самом деле не является байтовым массивом. Это просто последовательность из 17 байт, не более того. Этого недостаточно для .NET-массива. Таким образом, мы должны скопировать его в новый массив (возможно, стоит сохранить «буферные» массивы байтов и перезагрузить их, чтобы избежать распределения и освобождения). Это можно сделать либо через Marshal.Copy или какое-либо небезопасный указатель удовольствие:

byte[] bytes = new byte[17]; 

unsafe 
{ 
    IntPtr srcPtr = new IntPtr(bf.Bytes); 
    { 
    Marshal.Copy(srcPtr, bytes, 0, 17); 
    } 
} 

Это использует прямое копирование памяти, но делает некоторые проверки. В моем тестировании это отличный способ скопировать большие массивы (для меня точка безубыточности была где-то около 50 байт).Если ваш массив меньше, накладные расходы из этих проверок становятся выше по сравнению с общим временем копирования, так что вы можете использовать байты в байтах копирование вместо:

byte[] bytes = new byte[17]; 
unsafe 
{ 
    byte* srcPtr = bf.Bytes; 
    fixed (byte* bPtr = bytes) 
    { 
    var j = 0; 
    while (j++ < 17) 
    { 
     *(bPtr + j) = *(srcPtr++); 
    } 
    } 
} 

Я надеюсь, что я не должен сказать вам, чтобы быть осторожным в этом виде кода :)

В любом случае, я бы не стал беспокоиться о производительности слишком много, и я бы использовал вариант Marshal.Copy, просто потому, что ваш вызов БД будет бутылкой так или иначе. Безопасный вариант лучше :)

Там также несколько трюков, которые вы можете использовать, чтобы ускорить этот процесс, например, копирование целого int или long в то время, которое процессор намного лучше, хотя это сложнее. Попытка с помощью простого варианта (длина с кратным 4, копирование целого int за раз) сократила мое тестовое время выполнения на четыре. Если длина данных не кратна четырем, вы просто копируете остаток в виде байтов.

+0

Я не называю внешний метод. Мне буквально нужен буферный массив. – IamIC

+0

Хорошо, но для чего вам это нужно? Пожалуйста, дополните. – Luaan

+0

У меня есть база данных, которая принимает массив байтов. Мне нужно хранить числа в массиве, чтобы передать его в БД и изменить процесс. – IamIC