C# array within a struct

前端 未结 5 1022
余生分开走
余生分开走 2020-12-01 10:59

Want to do this: (EDIT: bad sample code, ignore and skip below)

struct RECORD {
    char[] name = new char[16];
    int dt1;
}
struct BLOCK {
    char[] ver         


        
相关标签:
5条回答
  • 2020-12-01 11:13

    I wouldn't use that pattern in the first place. This kind of memory mapping may be appropriate in c, but not in a high level language like C#.

    I'd just write a call to the binary reader for each member I want to read. This means you can use classes and write them in a clean high level way.

    It also takes care of endian issues. Whereas memory mapping will break when used on different endian systems.

    Related question: Casting a byte array to a managed structure


    So your code would look similar to the following (add access modifiers etc.):

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 11:17

    Using unsafe code and fixed size buffer this can be done: http://msdn.microsoft.com/en-us/library/zycewsya.aspx

    Fixed size buffers are inline-bytes of the struct. They don't live inside of a separate array like your char[] does.

    0 讨论(0)
  • 2020-12-01 11:23

    Use fixed size buffers:

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

    Alternativ you can just use the struct and read it with the following extension method:

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-01 11:25

    Unmanaged structures can contain embedded arrays. By default, these embedded array fields are marshaled as a SAFEARRAY. In the following example, s1 is an embedded array that is allocated directly within the structure itself.

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

    Arrays can be marshaled as UnmanagedType.ByValArray, which requires you to set the MarshalAsAttribute.SizeConst field. The size can be set only as a constant. The following code shows the corresponding managed definition of MyStruct. C#VB

    [StructLayout(LayoutKind.Sequential)]
    public struct MyStruct {
       [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] public short[] s1;
    }
    
    0 讨论(0)
  • 2020-12-01 11:31

    Unless you really need a struct, you can do this with a class. A class is basically a struct, and will be used exactly the same way, but it can contain methods inside. One of these methods is the constructor, which will initialize default values inside it once you create a new instance with "new". To create a constructor, put a method with the same name of the class inside it. It may receive arguments if you wish.

    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];
            }      
        }
    

    This way when you create a new item of type BLOCK, it will be pre-initialized:

    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
    
    0 讨论(0)
提交回复
热议问题