想要这样做: (编辑:错误的示例代码,忽略并跳过下面)
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];
}
但是无法在struct中声明数组大小,我该如何重新配置?
编辑:布局的原因是我使用BinaryReader读取用C结构编写的文件。使用BinaryReader和C#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
}
答案 0 :(得分:20)
[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();
}
}
答案 1 :(得分:6)
我不会首先使用该模式。这种内存映射可能适用于c,但不适用于高级语言,如C#。
我只是为我想读的每个成员写一个二进制阅读器的调用。这意味着您可以使用类并以干净的高级方式编写它们。
它还会处理字节序问题。而在不同的端系统上使用时,内存映射会中断。
相关问题:Casting a byte array to a managed structure
所以你的代码看起来类似于以下内容(添加访问修饰符等):
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 :(得分:6)
非托管结构可以包含嵌入式阵列。默认情况下,这些嵌入式数组字段被封送为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;
}
答案 3 :(得分:2)
使用不安全的代码和固定大小的缓冲区可以完成:http://msdn.microsoft.com/en-us/library/zycewsya.aspx
固定大小的缓冲区是struct的内联字节。它们不像char []那样生活在一个单独的数组中。
答案 4 :(得分:0)
除非您确实需要一个结构,否则可以使用一个类来完成。类基本上是一个结构,将以完全相同的方式使用,但它可以在内部包含方法。这些方法之一是构造函数,当您使用“ new”创建新实例时,它将在其中初始化默认值。要创建构造函数,请在其中放置与类具有相同名称的方法。如果您愿意,它可能会收到参数。
class RECORD
{
public int dt1;
public char[] name;
public RECORD => name = new char[16] // if it is one-line the {} can be =>
}
class BLOCK
{
public char[] version;
public int field1;
public int field2;
public RECORD[] records;
public char[] filler1;
public BLOCK()
{
records = new RECORD[15];
filler1 = new char[24];
version = new char[4];
}
}
这样,当您创建BLOCK类型的新项目时,它将被预先初始化:
var myblock = new BLOCK();
Console.WriteLine(myblock.records.Length); // returns 15
Console.WriteLine(myblock.records[0].Length); // returns 16
Console.WriteLine(myblock.filler1.Length); // returns 24