C # массив в структуре - PullRequest
       2

C # массив в структуре

23 голосов
/ 02 января 2012

Хочу сделать это: (РЕДАКТИРОВАТЬ: неверный пример кода, игнорировать и пропустить ниже)

struct RECORD {
    char[] name = new char[16];
    int dt1;
}
struct BLOCK {
    char[] version = new char[4];
    int  field1;
    int  field2;
    RECORD[] records = new RECORD[15];
    char[] filler1 = new char[24];
}

Но, будучи неспособным объявить размеры массива в структуре, как мне перенастроить это?

РЕДАКТИРОВАТЬ: причина для разметки в том, что я использую BinaryReader для чтения файла, написанного на структурах C. Используя BinaryReader и объединение структур C # (FieldOffset (0)), я хочу загрузить заголовок в виде байтового массива, а затем прочитать его так, как было задумано изначально.

[StructLayout(LayoutKind.Sequential)]
unsafe struct headerLayout
{
    [FieldOffset(0)]
    char[] version = new char[4];
    int fileOsn;
    int fileDsn;
    // and other fields, some with arrays of simple types
}

[StructLayout(LayoutKind.Explicit)]
struct headerUnion                  // 2048 bytes in header
{
    [FieldOffset(0)]
    public byte[] headerBytes;      // for BinaryReader
    [FieldOffset(0)]
    public headerLayout header;     // for field recognition
}

Ответы [ 4 ]

20 голосов
/ 02 января 2012

Использовать фиксированный размер буферов :

[StructLayout(LayoutKind.Explicit)]
unsafe struct headerUnion                  // 2048 bytes in header
{
    [FieldOffset(0)]
    public fixed byte headerBytes[2048];      
    [FieldOffset(0)]
    public headerLayout header; 
}

В качестве альтернативы вы можете просто использовать структуру и читать ее следующим методом расширения:

private static T ReadStruct<T>(this BinaryReader reader)
        where T : struct
{
    Byte[] buffer = new Byte[Marshal.SizeOf(typeof(T))];
    reader.Read(buffer, 0, buffer.Length);
    GCHandle handle = default(GCHandle);
    try
    {
        handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally
    {
        if (handle.IsAllocated) 
            handle.Free();
    }
}
6 голосов
/ 31 мая 2016

Неуправляемые структуры могут содержать встроенные массивы. По умолчанию эти поля встроенного массива маршалируются как SAFEARRAY. В следующем примере s1 является встроенным массивом, который выделяется непосредственно внутри самой структуры.

Unmanaged representation
struct MyStruct {
    short s1[128];
}

Массивы можно маршалировать как UnmanagedType.ByValArray, для чего необходимо установить поле MarshalAsAttribute.SizeConst. Размер можно установить только как константу. Следующий код показывает соответствующее управляемое определение MyStruct. C # VB

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
   [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] public short[] s1;
}
5 голосов
/ 03 января 2012

Я бы не стал использовать этот шаблон в первую очередь.Этот вид отображения памяти может быть уместным в c, но не на языке высокого уровня, таком как C #.

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

Это также решает проблемы с порядком байтов.Принимая во внимание, что отображение памяти будет прерываться при использовании в других системах с прямым порядком байтов.

Смежный вопрос: Приведение байтового массива к управляемой структуре


Таким образом, ваш код будет выглядеть аналогичнок следующему (добавьте модификаторы доступа и т. д.):

class Record
{
    char[] name;
    int dt1;
}
class Block {
    char[] version;
    int  field1;
    int  field2;
    RECORD[] records;
    char[] filler1;
}

class MyReader
{
    BinaryReader Reader;

    Block ReadBlock()
    {
        Block block=new Block();
        block.version=Reader.ReadChars(4);
        block.field1=Reader.ReadInt32();
        block.field2=Reader.ReadInt32();
        block.records=new Record[15];
        for(int i=0;i<block.records.Length;i++)
            block.records[i]=ReadRecord();
        block.filler1=Reader.ReadChars(24);
        return block;
    }

    Record ReadRecord()
    {
        ...
    }

    public MyReader(BinaryReader reader)
    {
        Reader=reader;
    }
}
2 голосов
/ 02 января 2012

Используя небезопасный код и буфер фиксированного размера, это можно сделать: http://msdn.microsoft.com/en-us/library/zycewsya.aspx

Буферы фиксированного размера - это встроенные байты структуры. Они не живут внутри отдельного массива, как ваш char [].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...