C#中的二进制序列化(实际上是WYSIWYG序列化)

| (对于“所见即所得”,我的意思是我决定写什么以及如何写,而不是Microsoft或Google的任何人)(好吧...从技术上讲我什么都不会决定...几年前编程的人决定,我只能问我必须跳多高) 今天我有点愚蠢,但是我已经浪费了两个小时寻找解决方案:-(。 现在... 我有一个二进制协议。它是基于C的,因此就像查看一个定义了计算机的字节序的C结构(幸运的是,它与\“ local \”字节序相同),其大小不同定义类型,定义数据结构对齐方式,定义结构布局,以已知编码将字符串固定为chars固定数组...一切都已定义!当您使用
[(LayoutKind.Explicit)]
时,一切都与C#
unsafe struct
非常相似,并且对数组使用
fixed
修饰符不是很挑剔。现在,我需要在C#中对其进行序列化/反序列化...我环顾了一下,但是却找不到任何东西...我错过了什么?在您问之前,我知道
BinaryFormatter
,但这对我来说还不够好...
BinaryFormatter
实现了其格式化语言。是的,我知道ѭ5(并且它没有实现big-endian的转换器),但这不是一个“完整”的解决方案。它只是“基础”工具。而且我知道
BinaryWriter
/
BinaryReader
,但是它们似乎不支持不是
byte[]
char[]
的数组,并且它们似乎无法在写入时“填充”数组(您有一个5个元素
byte[]
数组,您需要将其编写为10个元素
byte[]
数组,因为您使用的格式需要它...您必须编写代码行才能这样做) 计划B(甚至可能是计划Z)是为每个类创建一个影子
unsafe struct
,使用两个方法(
Read
Write
)创建
IWysiwygSerializable
接口,并在每个类中实现该接口(写入操作将填充ulate0ѭ并将其写入输出中流,读操作将相反)(或者我甚至可以在不使用ѭ20的情况下直接在
Read
Write
中执行数十个
BitConverter
,但对于数组则要困难一些) 谢谢!     
已邀请:
        我为声明性二进制序列化编写了一个相当简单但可扩展的框架。我在工作中已经广泛使用它,并且总是发现它节省了大量的精力: binaryserializer.com     
        不要使用BinaryFormatter。而是使用BinaryWriter和BinaryReader以所需的确切顺序将确切的字节写入要写入磁盘的磁盘。如果无法按照您喜欢的方式处理数组,那么您只需要自己遍历数组即可。为了使外观更整洁,您也许可以编写一个扩展方法来执行循环。     
        (请注意,这可能被视为广告,但是\“产品\”是MIT开源许可的,甚至其他引用的\“产品\”是MIT开源许可的)(请注意,我是广告的作者\“产品\”以及其他引用的\“产品\”) 没有任何“好”解决方案,所以我做了我的:-)我只好创建一个库来创建该库:FluentSerializer。该库可用于创建有关二进制数据序列化方式的“描述”。该描述以流畅的符号表示。您可以(通过我写的另一个库FluentStatement)在您的流利描述中包括所有常见的语句,例如
while
if
for
...(显然也使用了流利符号)。然后,您的描述将被编译为表达式树,然后被编译为一组动态方法(序列化数据的序列化,反序列化和大小)。 测试类的串行器的一小部分示例
/// <summary>
/// 
/// </summary>
public class Serializer : ISerializer<MyClass, EmptyParameters>
{
    #region ISerializer<MyClass,EmptyParameters> Members

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public Expression<Serializer<MyClass, EmptyParameters>> GetSerializer()
    {
        return (op, obj, par) => Statement.Start(fl => fl
            .Serialize(obj.Version)

            // Static objects can be serialized/deserialized.
            .Serialize(MyClass.StaticReadonlyInts1, typeof(FixedLength<>))

            // So can readonly collections.
            .Serialize(obj.ReadonlyInts1, typeof(FixedLength<>))

            // Both array and List<> (and Dictionary<,>, and SortedDictionary<,>, and
            // many other types of collections)
            ////.Serialize(obj.ReadonlyList1)
            .Serialize(obj.ReadonlyList1, typeof(VariableLengthByte<>))

            ////// Readonly fields can be serialized/deserialized.
            ////// Sadly you can\'t Dump() serializers that replace read only fields
            ////// (replace is the keyword here, readonly int X is a no-no, 
            ////// readonly List<int> X is a yes, readonly int[] X is a yes if it\'s 
            ////// FixedLength<>.
            ////.Serialize(obj.ReadonlyInt1)

            .Serialize(obj.Bool1)
            .Serialize(obj.Int2)

            // This will be serialized/deserialized only if obj.Version != 0
            // It\'s only an example of what you can do. You can use the full power of
            // FluentStatement, and remember that if instead of EmptyParameters you
            // had used another class as the parameters, you could have manipulated it
            // through the par object, so par.Version for example.
            .If(obj.Version != 0, fl.Serialize(obj.Int3))

            // This if(s) depend on the operation that is being done
            // (serialization/deserialization/size)
            .If(op == Operation.Serialize, fl.Serialize(obj.Int2))
            .If(op == Operation.Deserialize, fl.Serialize(obj.Int3))

            .Serialize(obj.Short1)

            // Tuples are supported.
            .Serialize(obj.Tuple1)

            // Arrays need to have the length prepended. There are helpers for this.
            // The default helper can be specified in the Serializer<T> constructor and
            // will be used if the field serializer isn\'t specified.
            ////.Serialize(obj.Ints1)

            // Or you can specify it:
            .Serialize(obj.Ints2, typeof(VariableLengthByte<>))
            .Serialize(obj.Ints3, typeof(VariableLengthByte<int[]>))

            // Nullable types are supported
            .Serialize(obj.NullableInt1, typeof(Nullable<int>))
            ////.Serialize(obj.NullableInt2)

            // But note that you could even use the Optional<> with value types,
            // usefull for example if you have to use a modifier that is a class
            // (like VariableLengthInt32 for example)
            .Serialize(obj.NullableInt1, typeof(Optional<int>))
            .Serialize(obj.NullableInt2, typeof(Optional<>))

            // So are \"optional\" objects (fields that can be null)
            // (Note that here if we wanted to specify the helper, we would have
            // to use typeof(Optional<VariableLengthByte<int>>)
            .Serialize(obj.OptionalInts1, typeof(Optional<VariableLengthInt32<int[]>>))
            .Serialize(obj.OptionalInts2, typeof(Optional<>))
            .Serialize(obj.OptionalList1, typeof(Optional<VariableLengthInt32<List<int>>>))
            .Serialize(obj.OptionalList2, typeof(Optional<>))

            // You can serialize a DateTime as the full .NET value
            .Serialize(obj.DateTime1)

            // Or, for example, as an Unix datetime (32 or 64 bits)
            .Serialize(obj.DateTime2, typeof(UnixDateTime<int>))

            .Serialize(obj.Float1)
            .Serialize(obj.Double1)
            .Serialize(obj.Decimal1)
            .Serialize(obj.TimeSpan1)

            // For strings it\'s a little more complex. There are too many combinations 
            // of possible formats (encoding x string length * (use char or byte length))
            // At this time there isn\'t any helper for C strings (null terminated strings).
            // You have to \"manually\" register you string formats.
            .Serialize(obj.String1, typeof(Program.MyUtf8VariableLengthInt32String))
            .Serialize(obj.String2, typeof(Program.MyAsciiVariableLengthInt32String))
            .Serialize(obj.String3, typeof(Program.MyUnicodeVariableLengthInt32String))

            // Chain serializing the base class can be done in this way
            .Serialize(obj, typeof(MySimpleClass))

            // This is only to make it easy to add new serialization fields. The last ) is
            // \"attached\" to the .Empty and doesn\'t need to be moved.
            .Empty());
    }

    #endregion
}
显然,仅当您必须对大量数据进行序列化/反序列化时,此库才是好的。如果您只有一个要序列化/反序列化的对象,那么
BinaryReader
/
BinaryWriter
可能就足够了(正如我在原始问题中所建议的那样,以及在Fantius的回答中所建议的)。     

要回复问题请先登录注册