Vra

Is daar 'n manier van kartering data wat ingesamel is op 'n stroom of skikking van 'n datastruktuur of andersom? In C ++ dit sou net 'n kwessie van besig om 'n wyser na die stroom as 'n tipe data wat ek wil om te gebruik (of andersom vir die omgekeerde) bv: in C ++

Mystruct * pMyStrct = (Mystruct*)&SomeDataStream;
pMyStrct->Item1 = 25;

int iReadData = pMyStrct->Item2;

natuurlik die C ++ manier is redelik onveilig tensy jy seker is van die kwaliteit van die stroom data vir lees inkomende data, maar vir uitgaande data is super vinnig en maklik.

Was dit nuttig?

Oplossing

Die meeste mense gebruik NET serialisasie (daar is vinniger binêre en stadiger XML formatter, hulle albei afhanklik van besinning en is weergawe verdraagsaam sekere mate)

As jy egter wil die vinnigste (onveilig) manier - waarom nie:

Die skryf:

YourStruct o = new YourStruct();
byte[] buffer = new byte[Marshal.SizeOf(typeof(YourStruct))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(o, handle.AddrOfPinnedObject(), false);
handle.Free();

Lees:

handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
o = (YourStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(YourStruct));
handle.Free();

Ander wenke

In die geval Luboš antwoord hasko was nie onveilig genoeg, daar is ook die regtig onveilige manier, met behulp van wysers in C #. Hier is 'n paar wenke en slaggate Ek het loop in:

using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;

// Use LayoutKind.Sequential to prevent the CLR from reordering your fields.
[StructLayout(LayoutKind.Sequential)]
unsafe struct MeshDesc
{
    public byte NameLen;
    // Here fixed means store the array by value, like in C,
    // though C# exposes access to Name as a char*.
    // fixed also requires 'unsafe' on the struct definition.
    public fixed char Name[16];
    // You can include other structs like in C as well.
    public Matrix Transform;
    public uint VertexCount;
    // But not both, you can't store an array of structs.
    //public fixed Vector Vertices[512];
}

[StructLayout(LayoutKind.Sequential)]
unsafe struct Matrix
{
    public fixed float M[16];
}

// This is how you do unions
[StructLayout(LayoutKind.Explicit)]
unsafe struct Vector
{
    [FieldOffset(0)]
    public fixed float Items[16];
    [FieldOffset(0)]
    public float X;
    [FieldOffset(4)]
    public float Y;
    [FieldOffset(8)]
    public float Z;
}

class Program
{
    unsafe static void Main(string[] args)
    {
        var mesh = new MeshDesc();
        var buffer = new byte[Marshal.SizeOf(mesh)];

        // Set where NameLen will be read from.
        buffer[0] = 12;
        // Use Buffer.BlockCopy to raw copy data across arrays of primitives.
        // Note we copy to offset 2 here: char's have alignment of 2, so there is
        // a padding byte after NameLen: just like in C.
        Buffer.BlockCopy("Hello!".ToCharArray(), 0, buffer, 2, 12);

        // Copy data to struct
        Read(buffer, out mesh);

        // Print the Name we wrote above:
        var name = new char[mesh.NameLen];
        // Use Marsal.Copy to copy between arrays and pointers to arrays.
        unsafe { Marshal.Copy((IntPtr)mesh.Name, name, 0, mesh.NameLen); }
        // Note you can also use the String.String(char*) overloads
        Console.WriteLine("Name: " + new string(name));

        // If Erik Myers likes it...
        mesh.VertexCount = 4711;

        // Copy data from struct:
        // MeshDesc is a struct, and is on the stack, so it's
        // memory is effectively pinned by the stack pointer.
        // This means '&' is sufficient to get a pointer.
        Write(&mesh, buffer);

        // Watch for alignment again, and note you have endianess to worry about...
        int vc = buffer[100] | (buffer[101] << 8) | (buffer[102] << 16) | (buffer[103] << 24);
        Console.WriteLine("VertexCount = " + vc);
    }

    unsafe static void Write(MeshDesc* pMesh, byte[] buffer)
    {
        // But byte[] is on the heap, and therefore needs
        // to be flagged as pinned so the GC won't try to move it
        // from under you - this can be done most efficiently with
        // 'fixed', but can also be done with GCHandleType.Pinned.
        fixed (byte* pBuffer = buffer)
            *(MeshDesc*)pBuffer = *pMesh;
    }

    unsafe static void Read(byte[] buffer, out MeshDesc mesh)
    {
        fixed (byte* pBuffer = buffer)
            mesh = *(MeshDesc*)pBuffer;
    }
}

As sy net aan beide kante:

dink jy moet binêre serialisasie gebruik en stuur die byte [] gevolg.

vertrou jou struct om ten volle blittable wees kan wees moeilikheid.

jy sal betaal in sommige oorhoofse (beide cpu en netwerk), maar sal veilig wees.

As jy nodig het om elke lid veranderlike vul met die hand kan jy dit veralgemeen 'n bietjie so ver as die primitiewes is bekommerd oor die gebruik van FormatterServices te haal ten einde die lys van veranderlike tipes wat verband hou met 'n voorwerp. Ek het gehad om dit te doen in 'n projek waar ek het 'n baie verskillende tipes boodskap kom uit die stroom en ek het beslis nie wil hê dat die serializer / deserializer vir elke boodskap skryf.

Hier is die kode wat ek gebruik om die deserialization uit 'n greep te veralgemeen [].

public virtual bool SetMessageBytes(byte[] message)
    {
        MemberInfo[] members = FormatterServices.GetSerializableMembers(this.GetType());
        object[] values = FormatterServices.GetObjectData(this, members);
        int j = 0;

        for (int i = 0; i < members.Length; i++)
        {
            string[] var = members[i].ToString().Split(new char[] { ' ' });
            switch (var[0])
            {
                case "UInt32":
                    values[i] = (UInt32)((message[j] << 24) + (message[j + 1] << 16) + (message[j + 2] << 8) + message[j + 3]);
                    j += 4;
                    break;
                case "UInt16":
                    values[i] = (UInt16)((message[j] << 8) + message[j + 1]);
                    j += 2;
                    break;
                case "Byte":
                    values[i] = (byte)message[j++];
                    break;
                case "UInt32[]":
                    if (values[i] != null)
                    {
                        int len = ((UInt32[])values[i]).Length;
                        byte[] b = new byte[len * 4];
                        Array.Copy(message, j, b, 0, len * 4);
                        Array.Copy(Utilities.ByteArrayToUInt32Array(b), (UInt32[])values[i], len);
                        j += len * 4;
                    }
                    break;
                case "Byte[]":
                    if (values[i] != null)
                    {
                        int len = ((byte[])values[i]).Length;
                        Array.Copy(message, j, (byte[])(values[i]), 0, len);
                        j += len;
                    }
                    break;
                default:
                    throw new Exception("ByteExtractable::SetMessageBytes Unsupported Type: " + var[1] + " is of type " +  var[0]);
            }
        }
        FormatterServices.PopulateObjectMembers(this, members, values);
        return true;
    }
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top