스트림 데이터를 C#의 데이터 구조에 매핑하기

스트림이나 배열에서 수집된 데이터를 데이터 구조에 매핑하거나 그 반대로 매핑할 수 있는 방법이 있나요? C++에서는 단순히 스트림에 대한 포인터를 사용하려는 데이터 유형으로 캐스팅하기만 하면 됩니다(또는 그 반대의 경우). 예: C++에서

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

int iReadData = pMyStrct->Item2;

들어오는 데이터를 읽을 때 스트림 데이터의 품질이 확실하지 않은 한 C++ 방식은 매우 안전하지 않지만, 나가는 데이터의 경우 매우 빠르고 쉽습니다.

해결책

대부분의 사람들은 .NET 직렬화를 사용합니다(더 빠른 바이너리와 더 느린 XML 포맷터가 있으며, 둘 다 리플렉션에 의존하고 어느 정도 버전에 내성이 있습니다).

그러나 가장 빠른(안전하지 않은) 방법을 원한다면 안 될 이유가 없습니다:

글쓰기:

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

읽기:

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

39 의 경우, 또한 충분히 안전하지 않은 오토메이티드 루보스 hasko& 상행담관염이라고 안전하지 않은 방법을 사용하여,

c # 에서 포인터. # 39 에 몇 가지 팁을 및 특히 I& # 39, ve here& 엘리가:


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] 
해설 (0)

양쪽에 .net이 있는 경우:

바이너리 직렬화를 사용하고 바이트[] 결과를 보내야 한다고 생각합니다.

구조체가 완전히 블리트가 가능하다고 믿는 것은 문제가 될 수 있습니다.

약간의 오버헤드(CPU와 네트워크 모두)가 발생하지만 안전합니다.

;

해설 (0)

각 멤버 변수를 수작업으로 채워야 하는 경우, 객체와 연관된 변수 유형 목록을 순서대로 검색하기 위해 FormatterServices를 사용하여 프리미티브에 관한 한 약간 일반화할 수 있습니다. 스트림에서 다양한 메시지 유형이 많이 나오는 프로젝트에서 이 작업을 수행해야 했는데, 각 메시지에 대해 직렬화기/역직렬화기를 작성하고 싶지 않았습니다.

다음은 바이트[]에서 역직렬화를 일반화하기 위해 사용한 코드입니다.


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] 
해설 (0)