【问题标题】:Deserialized object other than original serialized object原始序列化对象以外的反序列化对象
【发布时间】:2020-03-31 03:30:28
【问题描述】:

我正在使用 ASP Net Core 2.2

我序列化这个动态对象

var stuff1 = new
{
    Name = "John",
    Surname = "Smith",
    Addresses = new[] {
new { City = "New York", State = "NY"},
new { City = "Milano", State = "IT" }
};
var stuff1Serialized = JsonConvert.SerializeObject(stuff1)

这是序列化的对象:

{"Name":"John","Surname":"Smith"}

现在,我得到了这个字符串并反序列化了它

dynamic stuff1Deserialized = JsonConvert.DeserializeObject(stuff1Serialized);

我希望 sutff1 和 stuff1Deseralized 具有相同的结构,但它们不同,为什么?

在即时窗口中:

stuff1.name
"Jhon"

stuff1Deserialized.Name
{John}
    First: '((Newtonsoft.Json.Linq.JToken)stuff1Deserialized.Name).First' threw an exception of type 'System.InvalidOperationException'
    HasValues: false
    Last: '((Newtonsoft.Json.Linq.JToken)stuff1Deserialized.Name).Last' threw an exception of type 'System.InvalidOperationException'
    Next: null
    Parent: {"Name": "John"}
    Path: "Name"
    Previous: null
    Root: {{
  "Name": "John",
  "Surname": "Smith"
}}
    Type: String
    Value: "John"
    Results View: Expanding the Results View will enumerate the IEnumerable

我将对象与这个简单的 DotLiquid 模板一起使用:

Hello {{Name}} {{Surname}}. Number of Addresses: {{Addresses.size}} - {{Addresses[0].City}} - {{Addresses[1].City}}

使用 stuff1 对象,我得到了预期的结果:

Hello John Smith. Number of Addresses: 2 - New York - Milano

使用 stuff1Deserialized 对象我得到了这个结果:

Hello John Smith. Number of Addresses: 2 - -

【问题讨论】:

    标签: c# serialization


    【解决方案1】:

    根据评论更新

    我找到了一种方法:

    1 - 对象动态样本:

    dynamic dynamicStuff = new
    {
        Name = "John",
        Surname = "Smith",
        Obj = new { City = "New York", State = "NY" },// i add this to test object
        Addresses = new[]
        {
            new { City = "New York", State = "NY"},
            new { City = "Milano", State = "IT" }
        }
    };
    

    2 - 序列化和反序列化以构建动态对象:

    dynamic dynamicStuffDeSerialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(dynamicStuff));
    

    3 - 将dynamic 对象转换为JObject 并通过将JObject 转换为Dictionary 来构建(字符串,对象)的Dictionary

    Dictionary<string, object> keyValuePairs = ConvertJObject(JObject.FromObject(dynamicStuffDeSerialized));
    
    private static Dictionary<string, object> ConvertJObject(JObject jObject)
    {
        Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
        foreach (var property in jObject)
        {
            if (property.Value.Type == JTokenType.Array)
                keyValuePairs.Add(property.Key, ConvertJArray(property.Value.Select(o=>(JObject)o)));
    
            else if (property.Value.Type == JTokenType.Object)
                keyValuePairs.Add(property.Key, ConvertJObject((JObject)property.Value));
    
            else
                keyValuePairs.Add(property.Key, property.Value.ToString());
        }
    
        return keyValuePairs;
    }
    
    private static List<Dictionary<string, object>> ConvertJArray(IEnumerable<JObject> jObjects)
    {
        return jObjects.Select(o => ConvertJObject(o)).ToList();
    }
    

    请注意,您可以使用ToObjectJObject 转换为Dictionary,但它只是转换简单值而不是对象或数组,例如:

    JObject jObject = JObject.FromObject(dynamicStuffDeSerialized);
    Dictionary<string, object> dict = jObject.ToObject<Dictionary<string, object>>();
    

    4 - 使用Hash.FromDictionary 而不是Hash.FromAnonymousObject

    Template templatedynamicStuff = Template.Parse("Hello {{Name}} {{Surname}} City in Object {{Obj.City}}. Number of Addresses: {{Addresses.size}} - {{Addresses[0].City}} - {{Addresses[1].City}}");
    string result = templatedynamicStuff.Render(Hash.FromDictionary(keyValuePairs));
    

    请注意,我通过添加 City in Object {{Obj.City}} 更改了 template

    5 - 测试

    Console.WriteLine(result);
    

    6 - 结果

    Hello John Smith City in Object New York. Number of Addresses: 2 - New York - Milano
    

    旧答案

    根据 newtonsoft 文档,您可以使用 DeserializeAnonymousType 而不是 DeserializeObject反序列化匿名对象。但是DeserializeAnonymousType 需要 匿名 类型的definition 才能获得相同的对象

    如下代码:

    var stuff1 = new
    {
        Name = "John",
        Surname = "Smith"
    };
    
    var stuff1Serialized = JsonConvert.SerializeObject(stuff1);
    
    var definition = new { Name = "", Surname = "" };
    dynamic stuff1Deserialized = JsonConvert.DeserializeAnonymousType(stuff1Serialized, definition);
    

    根据评论更新

    您可以使用JObjectExpandoObject 获取属性namesvalues,如以下代码:

    dynamic stuff1 = new
    {
        Name = "John",
        Surname = "Smith"
    };
    
    var stuff1Serialized = JsonConvert.SerializeObject(stuff1);
    
    dynamic stuff1DeSerialized1 = JsonConvert.DeserializeObject(stuff1Serialized);
    
    foreach (JProperty property in JObject.FromObject(stuff1DeSerialized1))
    {
        Console.WriteLine($"Key:{property.Name}, Value:{property.Value}");
    }
    
    ExpandoObject stuff1DeSerialized2 = JsonConvert.DeserializeObject<ExpandoObject>(stuff1Serialized, new ExpandoObjectConverter());
    
    foreach(KeyValuePair<string, object> keyValue in stuff1DeSerialized2.ToList())
    {
        Console.WriteLine($"Key:{keyValue.Key}, Value:{keyValue.Value}");
    }
    

    希望能找到其他的解决方案与大家分享。

    【讨论】:

    • 谢谢你说。我的问题是我将收到一个通用 Json,我必须将其作为匿名对象传递给 DotLiquid 方法。我无法提前知道对象的类型
    • 是的,但是如果您不知道该对象具有或预期具有哪些参数,您打算如何使用它?
    • 谢谢你说。我必须将此对象传递给 DotLiquid,这是一个将 html 模板与数据合并的 html 模板引擎。您的解决方案适用于一级属性。但是,如果我添加子属性,DotLiquid 将无法识别子节点(请参阅更新帖子)。
    • 你能分享你的DotLiquid使用的模板
    • 抱歉耽搁了。我用我使用的简单模板更新了我的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 2013-02-22
    相关资源
    最近更新 更多