通用二进制读取器

And*_*per 6 .net c# binary deserialization

我正在编写二进制序列化器/ deserialser来将许多对象类型转换为字节流.对象表示通过蓝牙或USB连接的设备的API命令及其相关响应.我正在使用BinaryWriter&BinaryReader来写入/读取流.

序列化器很简单.要序列化的特性标记有一个属性,该属性指定将它们写入字节流的顺序.我使用反射和重载分辨率句柄迭代属性,选择正确的Write(...)方法BinaryWriter.

解串器并不那么简单.我再次可以遍历特定响应类中的特性,我期望确定需要从流中读取的类型.棘手的一点就是选择正确的方法调用BinaryReader来读取我需要的值.我想到了两种方法.

  1. 一个大的switch语句,它ReadXXXX()根据要读取的类型调用正确的方法.
  2. 使用我需要的类型的名称来在字符串中构建我需要的方法的名称,然后使用relection调用该方法.

我有没有想到更简单的方法?根据您想要的返回类型,您无法进行重载解析,这简直太遗憾了.

por*_*ges 1

我在二进制反序列化器中使用了选项 1(大 switch 语句)。更干净的方法可能是这样的:

{
    object result;

    BinaryReader ...;
    foreach (var propertyInfo in ...)
    {
        Func<BinaryReader, object> deserializer;
        if (!supportedTypes.TryGetValue(propertyInfo.PropertyType, out deserializer))
        {
            throw new NotSupportedException(string.Format(
                "Type of property '{0}' isn't supported ({1}).", propertyInfo.Name, propertyInfo.PropertyType));
        }

        var deserialized = deserializer(reader);
        propertyInfo.SetValue(result, deserialized, null);
    }
}

private static Dictionary<Type, Func<BinaryReader, object>> supportedTypes = new Dictionary<Type, Func<BinaryReader, object>>
{
    { typeof(int), br => br.ReadInt32() },
    // etc
};
Run Code Online (Sandbox Code Playgroud)

另一种选择是让命令类本身进行序列化:

interface IBinarySerializable
{
    void Serialize(BinaryWriter toStream);
    void Deserialize(BinaryReader fromStream);
}
Run Code Online (Sandbox Code Playgroud)

然后在你的命令中:

abstract class Command : IBinarySerializable
{

}

class SomeCommand : Command
{
    public int Arg1 { get; set; }

    public void Serialize(BinaryWriter toStream)
    {
        toStream.Write(Arg1);
    }

    public void Deserialize(BinaryReader fromStream)
    {
        Arg1 = fromStream.ReadInt32();
    }
}
Run Code Online (Sandbox Code Playgroud)

以及通用序列化方法:

void Serialize<T>(T obj) where T : IBinarySerializable
{
    obj.Serialize(_stream);
}

T Deserialize<T>() where T : new(), IBinarySerializable
{
    var result = new T();
    result.Deserialize(_stream);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但这样你可能最终会重复一些代码。(另一方面,如果这在您的场景中有意义,则派生类可以调用其父类版本的序列化/反序列化,并且效果很好。)