Protobuf-net:如何序列化复杂的集合?

Lir*_*man 3 c# serialization protobuf-net

我正在尝试使用protobuf-net序列化这种类型的对象:

[ProtoContract]
public class RedisDataObject
{
    [ProtoMember(1)]
    public string DataHash;
    [ProtoMember(2, DynamicType = true)]
    public Dictionary<ContextActions, List<Tuple<string, List<object>>>> Value;
}

[Serializable]
public enum ContextActions
{
    Insert,
    Update,
    Delete
}
Run Code Online (Sandbox Code Playgroud)

我正在使用,List<object>因为我在我的代码中存储了其他类的不同类实例.

但我收到此错误消息:

Unable to resolve a suitable Add method for System.Collections.Generic.Dictionary...
Run Code Online (Sandbox Code Playgroud)

这显然是因为字典,但我找不到解决方案如何解决这个问题.

dbc*_*dbc 5

您的基本问题是DynamicType = true仅适用于该特定属性,并仅序列化该特定属性值的类型信息.它不会递归地应用于该对象包含的任何属性.但是,您的object值嵌套在容器的多个级别内:

public Dictionary<ContextActions, List<Tuple<string, List<object>>>> Value;
Run Code Online (Sandbox Code Playgroud)

您需要做的是序列化object列表元组字典中的每个类型信息.您可以通过引入代理值类型来执行此操作:

[ProtoContract]
public struct DynamicTypeSurrogate<T>
{
    [ProtoMember(1, DynamicType = true)]
    public T Value { get; set; }
}

public static class DynamicTypeSurrogateExtensions
{
    public static List<DynamicTypeSurrogate<T>> ToSurrogateList<T>(this IList<T> list)
    {
        if (list == null)
            return null;
        return list.Select(i => new DynamicTypeSurrogate<T> { Value = i }).ToList();
    }

    public static List<T> FromSurrogateList<T>(this IList<DynamicTypeSurrogate<T>> list)
    {
        if (list == null)
            return null;
        return list.Select(i => i.Value).ToList();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后修改您RedisDataObject的序列化代理字典,如下所示:

[ProtoContract]
public class RedisDataObject
{
    [ProtoMember(1)]
    public string DataHash;

    [ProtoIgnore]
    public Dictionary<ContextActions, List<Tuple<string, List<object>>>> Value;

    [ProtoMember(2)]
    private Dictionary<ContextActions, List<Tuple<string, List<DynamicTypeSurrogate<object>>>>> SurrogateValue
    {
        get
        {
            if (Value == null)
                return null;
            var dictionary = Value.ToDictionary(
                p => p.Key,
                p => (p.Value == null ? null : p.Value.Select(i => Tuple.Create(i.Item1, i.Item2.ToSurrogateList())).ToList()));
            return dictionary;
        }
        set
        {
            if (value == null)
                Value = null;
            else
            {
                Value = value.ToDictionary(
                    p => p.Key,
                    p => (p.Value == null ? null : p.Value.Select(i => Tuple.Create(i.Item1, i.Item2.FromSurrogateList())).ToList()));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

另请注意这里DynamicType提到的限制:

DynamicType- 存储Type类型的附加信息(默认情况下,它包括AssemblyQualifiedName,虽然这可以由用户控制).这使得可以序列化弱模型,即object用于属性成员的位置,但是目前这仅限于契约类型(不是基元),并且不适用于具有继承的类型(这些限制可能在以后被删除).与之相同AsReference,它使用了非常不同的布局格式

虽然上述文档存在于以前的项目站点并且尚未移至当前站点,但从版本2.0.0.668开始,对非合同类型的限制仍然存在.(我测试了intList<object>失败添加值;我还没有检查对继承的限制是否仍然存在.)