我正在编写二进制序列化器/反序列化器,以便将许多对象类型转换为字节流。这些对象表示通过蓝牙或USB连接的设备的API命令及其相关响应。我正在使用BinaryWriter&BinaryReader对流进行写/读操作。
序列化程序很简单。要序列化的属性被标记为一个属性,该属性指定它们写入字节流的顺序。我使用反射和重载分辨率处理来迭代属性,选择正确的Write(...)方法。
反序列化程序并不那么简单。再次,我可以迭代特定响应类中的属性,以确定需要从流中读取的类型。棘手的是选择正确的方法来调用BinaryWriter来读取我需要的值。我想到了两种方法。
根据要读取的类型调用正确BinaryReader方法的大switch语句。
使用我需要的类型的名称在字符串中构建我需要的方法的名称,然后使用relection调用该方法。
有没有一种更简单的方法我不去想?很遗憾,不能根据所需的返回类型执行重载解析。

最佳答案

我在二进制反序列化程序中使用了选项1(big 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
};

另一个选项是让命令类自己进行序列化:
interface IBinarySerializable
{
    void Serialize(BinaryWriter toStream);
    void Deserialize(BinaryReader fromStream);
}

然后在你的命令下:
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();
    }
}

和泛型序列化方法:
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;
}

但这样你可能会复制一些代码。(另一方面,派生类可以调用其父类的serialize/deserialize版本,如果这在您的场景中有意义,并且工作得很好。)

07-26 08:36