动态对象序列化

Rai*_*ine 22 c# serialization dynamic protobuf-net

我尝试DynamicObjectBinaryFormatter,但是:序列化一个类

  • 输出文件太大,不完全是对线路友好的
  • 循环引用未处理(序列化时卡住)

由于序列化一个单独的DynamicObject手段,这里是我尝试序列化的类:

[Serializable()]
class Entity
    : DynamicObject, ISerializable
{

    IDictionary<string, object> values = new Dictionary<string, object>();

    public Entity()
    {

    }

    protected Entity(SerializationInfo info, StreamingContext ctx)
    {
        string fieldName = string.Empty;
        object fieldValue = null;

        foreach (var field in info)
        {
            fieldName = field.Name;
            fieldValue = field.Value;

            if (string.IsNullOrWhiteSpace(fieldName))
                continue;

            if (fieldValue == null)
                continue;

            this.values.Add(fieldName, fieldValue);
        }

    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        this.values.TryGetValue(binder.Name, out result);

        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        this.values[binder.Name] = value;

        return true;
    }        

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {            
        foreach (var kvp in this.values)
        {
            info.AddValue(kvp.Key, kvp.Value);                 
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

(我想我可以使用ExpandoObject,但这是另一个故事.)

这是一个简单的测试程序:

    static void Main(string[] args)
    {
        BinaryFormatter binFmt = new BinaryFormatter();

        dynamic obj = new Entity();
        dynamic subObj = new Entity();
        dynamic obj2 = null;

        obj.Value = 100;
        obj.Dictionary = new Dictionary<string, int>() { { "la la la", 1000 } };

        subObj.Value = 200;
        subObj.Name = "SubObject";

        obj.Child = subObj;

        using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate))
        {
            binFmt.Serialize(stream, obj);                
        }

        using (var stream = new FileStream("test.txt", FileMode.Open))
        {
            try
            {
                obj2 = binFmt.Deserialize(stream);                    
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }                
        }

        Console.ReadLine();

    }
Run Code Online (Sandbox Code Playgroud)

在这里放一些断点帮助我看看obj2的内容,看起来原始数据被正确反序列化,但如果你有想象力并移动数据,就会出现上述缺点.

我看了一下Marc Gravell的protobuf-net,但我不确定如何在这样的环境中使用它(我甚至不确定我从存储库中选择了正确的版本,但是嘿).

我知道它的代码多于单词,但我认为我不能更好地解释这种情况.请告诉我是否可以添加一些内容以使此问题更清晰.

任何帮助深表感谢.

sgt*_*gtz 12

我98%确定这个序列适用于动态对象.

  1. 将对象转换为Expando对象
  2. 将expando对象转换为Dictionary类型
  3. 按照正常使用ProtoBuf-net Serializer.Serialize/.Deserialize
  4. 将字典转换为Expando对象

您可以将对象转换为名称/值对的集合以进行传输.

这只是动态可以做的一小部分,但也许对你来说已经足够了.

有一些自定义代码可以处理上面的一些转换,如果有兴趣我可以告诉你.

当动态是一个类的占位符时,我没有解决方案.对于这种情况,我建议获取类型并使用switch语句按需要序列化/反序列化.对于最后一种情况,您需要放置一些东西来指示您需要哪种类型的通用反序列化(字符串/ id /完全限定类型名称/等).假设您正在处理预期类型的​​列表.

注意:Expando实现了IDictionary.Expando仅仅是键/值对的列表.即.你所关注的是键,值是从任何函数链实现的返回.有一组动态界面可以自定义语法糖体验,但大多数时候你不会看到它们.

裁判:

  • 是的,有些代码真的很棒! (2认同)

Nat*_*ten 10

我不确定JSON在您的Senario中是否可以接受,但如果是,我使用Json.net(http://json.codeplex.com)来序列化动态类型.它运行良好,速度快,输出尺寸小.虽然Json.net不直接返回动态对象,但很容易将Json.Net的反序列化输出转换为任何动态类型.在下面的示例中,我使用ExpandoObject作为我的动态类型.下面的代码是我在Facebook Graph Toolkit中使用的代码.请参阅此链接以获取原始来源:http://facebookgraphtoolkit.codeplex.com/SourceControl/changeset/view/48442#904504

public static dynamic Convert(string s) {
            object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(s);
            if (obj is string) {
                return obj as string;
            } else {
                return ConvertJson((JToken)obj);
            }
    }

    private static dynamic ConvertJson(JToken token) {
        // FROM : http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx
        // Ideally in the future Json.Net will support dynamic and this can be eliminated.
        if (token is JValue) {
            return ((JValue)token).Value;
        } else if (token is JObject) {
            ExpandoObject expando = new ExpandoObject();
            (from childToken in ((JToken)token) where childToken is JProperty select childToken as JProperty).ToList().ForEach(property => {
                ((IDictionary<string, object>)expando).Add(property.Name, ConvertJson(property.Value));
            });
            return expando;
        } else if (token is JArray) {
            List<ExpandoObject> items = new List<ExpandoObject>();
            foreach (JToken arrayItem in ((JArray)token)) {
                items.Add(ConvertJson(arrayItem));
            }
            return items;
        }
        throw new ArgumentException(string.Format("Unknown token type '{0}'", token.GetType()), "token");
    }
Run Code Online (Sandbox Code Playgroud)

  • 在针对我的问题尝试了几种不同的解决方案后,您的代码就是执行我需要的代码.所以,虽然你的回答可能没有像我那样帮助OP,但我仍然很感激找到它!:) (2认同)