简体   繁体   English

C# - struct serialization

[英]C# - struct serialization

I have got a small class that I would like to use for serializing structs. 我有一个小类,我想用它来序列化结构。 I would like to know two things: 我想知道两件事:

  • Performance issue. 性能问题。 Since I am passing Object - it passes just a reference, not a copy of the struct? 因为我传递了Object - 它只传递一个引用,而不是结构的副本? And since I am returning object of type T it also only passes a reference? 既然我要返回T类型的对象,它也只传递一个引用?

  • Correctness issue. 正确性问题。 Will this serialization work for all structs? 这个序列化是否适用于所有结构? I mean - is there a possibility where those methods will not work? 我的意思是 - 这些方法有可能不起作用吗?

     public static byte[] ToByteArray(Object obj) { int size = Marshal.SizeOf(obj); byte[] arr = new byte[size]; IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(obj, ptr, true); Marshal.Copy(ptr, arr, 0, size); Marshal.FreeHGlobal(ptr); return arr; } public static T ToStructure<T>(byte[] arr) where T : new() { T str = new T(); int size = Marshal.SizeOf(str); IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.Copy(arr, 0, ptr, size); str = (T)Marshal.PtrToStructure(ptr, str.GetType()); Marshal.FreeHGlobal(ptr); return str; } 

Thanks, guys! 多谢你们!

EDIT 编辑

I now specify that these are structs. 我现在指定这些是结构。 Nothing is being copied now? 现在什么都没有被复制?

    public static byte[] ToByteArray<T>(ref T str) where T : struct
    {
        int size = Marshal.SizeOf(str);
        byte[] arr = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.StructureToPtr(str, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);

        return arr;
    }

    public static T ToStructure<T>(byte[] arr) where T : struct
    {
        T str = default(T);

        int size = Marshal.SizeOf(str);
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.Copy(arr, 0, ptr, size);
        str = (T)Marshal.PtrToStructure(ptr, str.GetType());
        Marshal.FreeHGlobal(ptr);

        return str;
    }
  1. This will not serialize references correctly (ie any field of a non-primitive and non-struct type). 这不会正确地序列化引用(即非原始类型和非结构类型的任何字段)。
  2. It doesn't include type data 它不包括类型数据
    • Which makes it unsuitable for cases when not all types are known beforehand or some types have changed slightly since serialization time. 这使得它不适用于事先不知道所有类型或某些类型自序列化时间以来稍微改变的情况。
  3. (Minor) ToStructure doesn't validate the binary data (次要) ToStructure不验证二进制数据

Why not learn about the existing solutions before reinventing the wheel? 在重新发明轮子之前,为什么不了解现有的解决方案呢? The Serialization Guidelines article says there are 3 serialization techniques implemented in the .NET framework that have different characteristics and are tailored for different purposes. 序列化指南文章称,.NET框架中实现了3种序列化技术,这些技术具有不同的特性,并且针对不同的目的进行了定制。

Here's an example of the simplest, 3rd technique given as example in the Object Serialization in .NET article. 下面是.NET中的Object Serialization一文中给出的最简单的第三种技术示例。 It exists to reconstruct an object with exactly the same type and internal data as the original one (which means, serialization includes the objects it references). 存在用于重建具有与原始对象完全相同的类型和内部数据的对象(这意味着,序列化包括它引用的对象)。
(the code is in IronPython yet I hope it's readable enough to understand what's going on) (代码在IronPython中,但我希望它足够可读,以了解发生了什么)

>>> l=System.Collections.Generic.List[System.Drawing.Point]\
([System.Drawing.Point(*(random.randint(1,1000) for _ in range(2))) for _ in range(5)])
>>> l
List[Point]([<System.Drawing.Point object at 0x0000000000000233 [{X=491,Y=874}]>
, <System.Drawing.Point object at 0x0000000000000234 [{X=819,Y=595}]>, <System.D
rawing.Point object at 0x0000000000000235 [{X=456,Y=625}]>, <System.Drawing.Poin
t object at 0x0000000000000236 [{X=583,Y=29}]>, <System.Drawing.Point object at
0x0000000000000237 [{X=329,Y=212}]>])
>>> szr=System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
>>> stm=System.IO.MemoryStream()
>>> szr.Serialize(stm,l)
>>> stm.Length
481L
>>> bytes=stm.GetBuffer()
>>> s=''.join(chr(b) for b in bytes)
>>> s
u'\x00\x01\x00\x00\x00\xff\xff\xff\xff\x01\x00\x00\x00\x00\x00\x00\x00\x0c\x02\x
00\x00\x00QSystem.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f
5f7f11d50a3a\x04\x01\x00\x00\x00\x8c\x01System.Collections.Generic.List`1[[Syste
m.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToke
n=b03f5f7f11d50a3a]]\x03\x00\x00\x00\x06_items\x05_size\x08_version\x04\x00\x00\
x16System.Drawing.Point[]\x02\x00\x00\x00\x08\x08\t\x03\x00\x00\x00\x05\x00\x00\
x00\x00\x00\x00\x00\x07\x03\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x04\
x14System.Drawing.Point\x02\x00\x00\x00\x05\xfc\xff\xff\xff\x14System.Drawing.Po
int\x02\x00\x00\x00\x01x\x01y\x00\x00\x08\x08\x02\x00\x00\x00\xeb\x01\x00\x00j\x
03\x00\x00\x01\xfb\xff\xff\xff\xfc\xff\xff\xff3\x03\x00\x00S\x02\x00\x00\x01\xfa
\xff\xff\xff\xfc\xff\xff\xff\xc8\x01\x00\x00q\x02\x00\x00\x01\xf9\xff\xff\xff\xf
c\xff\xff\xffG\x02\x00\x00\x1d\x00\x00\x00\x01\xf8\xff\xff\xff\xfc\xff\xff\xffI\
x01\x00\x00\xd4\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
  1. It WILL copy. 它会复制。 This is called "boxing". 这被称为“拳击”。 The only way to pass a reference to a struct S is to have a parameter declared as ref S. 传递对结构S的引用的唯一方法是将参数声明为ref S.
  2. It wont handled nested stuff such as members that are array, string or any class type. 它不会处理嵌套的东西,例如数组,字符串或任何类类型的成员。

FYI With generics you can constrain a method to just apply to structs with "where T:struct" 仅供参考使用泛型,您可以将方法约束为仅应用于“where T:struct”的结构

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM