Mapping-Stream-Daten auf Datenstrukturen in C #

stimmen
20

Gibt es eine Möglichkeit der Kartierungsdaten gesammelt auf einem Stream oder Array auf eine Datenstruktur oder umgekehrt? In C ++ ist dies einfach eine Sache sein, einen Zeiger auf den Stream als einen Datentyp Gießen I (oder umgekehrt für die Rückwärts) zB verwendet werden soll: in C ++

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

int iReadData = pMyStrct->Item2;

offensichtlich der C ++ Weg ist ziemlich unsicher, wenn Sie sicher von der Qualität der Stromdaten sind bei eingehenden Daten zu lesen, aber für abgehende Daten ist super schnell und einfach.

Veröffentlicht am 05/08/2008 um 14:11
quelle vom benutzer
In anderen Sprachen...                            


4 antworten

stimmen
16

Die meisten Leute benutzen .NET Serialisierung (es schneller binär ist und langsamer XML-Formatierer, sie beide sind abhängig von Reflexion und sind Version tolerant zu gewissen Grad)

Wenn Sie jedoch die schnellste (unsicher) Art und Weise wollen - warum nicht:

Schreiben:

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();

Lesen:

handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
o = (YourStruct)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(YourStruct));
handle.Free();
Beantwortet am 05/08/2008 um 16:46
quelle vom benutzer

stimmen
5

Im Fall lubos Hasko Antwort genug nicht unsicher war, gibt es auch die wirklich unsichere Art und Weise, mit Zeigern in C #. Hier einige Tipps und Fallen ich habe laufen 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;
    }
}
Beantwortet am 24/10/2009 um 12:37
quelle vom benutzer

stimmen
2

Wenn Sie jedes Mitglied Variable von Hand füllen möchten, können Sie es ein wenig verallgemeinern so weit wie die Primitiven unter Verwendung FormatterServices betroffen sind, um die Liste der Variablentypen mit einem Objekt zugeordnet abzurufen. Ich hatte dies in einem Projekt zu tun, wo ich den Strom eine Menge verschiedenen Nachrichtentypen hatte scheiden aus und ich wollte auf keinen Fall den Serializer / Deserializer für jede Nachricht schreiben.

Hier ist der Code, den ich verwenden, um die Deserialisierung von einem byte [] zu verallgemeinern.

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;
    }
Beantwortet am 05/08/2008 um 14:47
quelle vom benutzer

stimmen
2

Wenn es .net auf beiden Seiten:

denken Sie binäre Serialisierung verwenden und die byte [] Ergebnis senden soll.

Vertrauen auf Ihre Struktur vollständig blitfähig seinen Ärger sein kann.

Sie werden in einem gewissen Overhead (beide CPU und Netzwerk) zahlen, aber sicher sein.

Beantwortet am 05/08/2008 um 14:29
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more