С# массив внутри структуры
Хотите сделать это:
(EDIT: неверный код примера, игнорировать и пропустить ниже)
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];
}
Но не имея возможности объявить размеры массива в структуре, как мне перенастроить это?
EDIT: причина для макета - я использую BinaryReader для чтения файла, написанного с помощью C-структур. Используя BinaryReader и С# struct union (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
}
Ответы
Ответ 1
Я бы не использовал этот шаблон в первую очередь. Такое сопоставление памяти может быть уместным в c, но не на языке высокого уровня, таком как С#.
Я бы просто написал вызов двоичному читателю для каждого члена, которого я хочу прочитать. Это означает, что вы можете использовать классы и записывать их на высоком уровне.
Он также заботится о проблемах с эндией. В то время как отображение памяти будет ломаться при использовании в разных системах endian.
Связанный вопрос: Передача байтового массива в управляемую структуру
Итак, ваш код будет похож на следующий (добавьте модификаторы доступа и т.д.):
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
Используйте буферы фиксированного размера:
[StructLayout(LayoutKind.Explicit)]
unsafe struct headerUnion // 2048 bytes in header
{
[FieldOffset(0)]
public fixed byte headerBytes[2048];
[FieldOffset(0)]
public headerLayout header;
}
Alternativ вы можете просто использовать структуру и прочитать ее с помощью следующего метода расширения:
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();
}
}
Ответ 3
Массивы внутри структур
Неуправляемые структуры могут содержать встроенные массивы. По умолчанию эти поля встроенных массивов маршалируются как SAFEARRAY. В следующем примере s1 представляет собой встроенный массив, который распределяется непосредственно внутри самой структуры.
Unmanaged representation
struct MyStruct {
short s1[128];
}
Массивы могут быть маршалированы как UnmanagedType.ByValArray, что требует установки поля MarshalAsAttribute.SizeConst. Размер может быть установлен только как константа. Следующий код показывает соответствующее управляемое определение MyStruct.
С#, VB
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] public short[] s1;
}
Ответ 4
используйте конструктор с Параметры:
public struct RECORD {
public RECORD(int initial) {
name = new char[16];
dt1 = initial;
}
public char[] name;
public int dt1;
}
...
var record = new RECORD(5);
Ответ 5
Использование небезопасного кода и буфера фиксированного размера это можно сделать: http://msdn.microsoft.com/en-us/library/zycewsya.aspx
Буферы фиксированного размера являются встроенными байтами структуры. Они не живут внутри отдельного массива, как ваш char [] делает.