【问题标题】:JSON.Net deserialization error setting value to propertyJSON.Net 反序列化错误将值设置为属性
【发布时间】:2015-05-10 18:04:48
【问题描述】:

我想对以下模型进行序列化/反序列化:

public class ReadabilitySettings
{
    public ReadabilitySettings() {
    }

    private bool _reababilityEnabled;
    public bool ReadabilityEnabled {
        get {
            return _reababilityEnabled;
        }
        set {
            _reababilityEnabled = value;
        }
    }

    private string _fontName;
    public string FontName { 
        get {
            return _fontName;
        }
        set {
            _fontName = value;
        }
    }

    private bool _isInverted;
    public bool IsInverted {
        get {
            return _isInverted;
        }
        set {
            _isInverted = value;
        }
    }

    public enum FontSizes
    {
        Small = 0,
        Medium = 1,
        Large = 2
    }

    private FontSizes _fontSize;
    public FontSizes FontSize { get
        {
            return _fontSize;
        }
        set 
        { 
            _fontSize = value;
        }
    }
}
}

我有一个包含以下对象实例的列表:

public class CacheItem<T>
{
    public string Key { get; set; }
    public T Value { get; set; }
}

我这样填充列表:

list.Add(new CacheItem<ReadabilitySettings>() { Key = "key1", Value = InstanceOfReadabilitySettings };

当我想序列化这个列表时,我会调用:

var json = JsonConvert.SerializeObject (list);

这很好用。没有错误。它给出了以下 json:

[{"Key":"readbilitySettings","Value":{"ReadabilityEnabled":true,"FontName":"Lora","IsInverted":true,"FontSize":2}}]

当我想反序列化我调用的列表时:

var list = JsonConvert.DeserializeObject<List<CacheItem<object>>> (json);

这给了我一个 CacheItem 的列表,它的 Value 属性设置为一个 JObject。到目前为止没有错误。

当我想要调用 ReadabilitySettings 的实际实例时:

var settings = JsonConvert.DeserializeObject<ReadabilitySettings> (cacheItem.Value.ToString ());

我必须调用它,因为 cacheItem.Value 设置为 json 字符串,而不是 ReadabilitySettings 的实例。 json字符串为:

{{   "ReadabilityEnabled": true,   "FontName": "Lora",   "IsInverted": true,   "FontSize": 2 }} Newtonsoft.Json.Linq.JObject

然后我收到此错误:“在 'Reflect.Mobile.Shared.State.ReadabilitySettings' 上将值设置为 'ReadabilityEnabled' 时出错。”

我错过了什么?谢谢!

编辑------

这是引发错误的方法:

    public T Get<T> (string key)
    {
        var items = GetCacheItems (); // this get the initial deserialized list of CacheItems<object> with its value property set to a JObject
        if (items == null)
            throw new CacheKeyNotFoundException ();
        var item = items.Find (q => q.Key == key);
        if (item == null)
            throw new CacheKeyNotFoundException ();
        var result = JsonConvert.DeserializeObject<T> (item.Value.ToString ()); //this throws the error
        return result;
    }

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    我刚刚尝试过,这几乎是复制/粘贴您的代码,并且使用 Newtonsoft.Json v6.0.0.0(来自 NuGet)可以正常工作:

    var list = new List<CacheItem<ReadabilitySettings>>();
    list.Add(new CacheItem<ReadabilitySettings>() { Key = "key1", Value = new ReadabilitySettings() { FontName = "FontName", FontSize = ReadabilitySettings.FontSizes.Large, IsInverted = false, ReadabilityEnabled = true } });
    
    var json = JsonConvert.SerializeObject(list);
    var list2 = JsonConvert.DeserializeObject<List<CacheItem<object>>>(json);
    var settings = JsonConvert.DeserializeObject<ReadabilitySettings>(list2.First().Value.ToString());
    

    但是,您不需要最后一行。只需在对DeserializeObject 的调用中将List&lt;CacheItem&lt;object&gt;&gt; 切换为List&lt;CacheItem&lt;ReadabilitySettings&gt;&gt;,它就会自动解决它:

    var list2 = JsonConvert.DeserializeObject<List<CacheItem<ReadabilitySettings>>>(json);
    

    现在list2.First().Value.GetType() = ReadabilitySettings 无需进一步反序列化。你使用对象有什么原因吗?


    编辑:

    我不确定这是否对您有帮助,但考虑到您正在尝试做的事情,您是否考虑过使用自定义转换器?出于类似的原因,我几天前不得不这样做。我的 JSON 中返回了一个枚举属性(类似于您的密钥),它提示了我的 JSON 中的属性是什么类型,因此我的反序列化类是什么类型。我的类中的属性是一个接口而不是一个对象,但同样的原则也适用于你。

    我使用了一个自定义转换器来自动处理干净地创建正确类型的对象。

    这是适用于您的场景的 CustomConverter。如果您的密钥设置为 readbilitySettings,则 result.Value 将初始化为 ReadabilitySettings

    public class CacheItemConverter : CustomCreationConverter<CacheItem<object>>
    {
        public override CacheItem<object> Create(Type objectType)
        {
            return new CacheItem<object>();
        }
    
        public CacheItem<object> Create(Type objectType, JObject jObject)
        {
            var keyProperty = jObject.Property("Key");
            if (keyProperty == null)
                throw new ArgumentException("Key missing.");
    
            var result = new CacheItem<object>();
    
            var keyValue = keyProperty.First.Value<string>();
            if (keyValue.Equals("readbilitySettings", StringComparison.InvariantCultureIgnoreCase))
                result.Value = new ReadabilitySettings();
            else
                throw new ArgumentException(string.Format("Unsupported key {0}", keyValue));
    
            return result;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jObject = JObject.Load(reader);
            var target = Create(objectType, jObject);
            serializer.Populate(jObject.CreateReader(), target);
    
            /* Here your JSON is deserialised and mapped to your object */
    
            return target;
        }
    }
    

    用法:

    var list = JsonConvert.DeserializeObject<List<CacheItem<object>>>(json, new CacheItemConverter());
    

    这是一个完整的工作示例的链接: http://pastebin.com/PJSvFDsT

    【讨论】:

    • 我也无法使用 Json.NET 6.0.8 重现这一点。 @Corstiaan 可能在做 JsonConvert.DeserializeObject&lt;List&lt;CacheItem&lt;object&gt;&gt;&gt;,因为他/她正在反序列化一个多态列表,并在反序列化值之前检查 CacheItem.Key 中的类型。
    • 感谢您迄今为止的宝贵时间。 Dbc 是对的——我使用 是因为我需要在 CacheItem 的 Value 字段中存储许多不同的类型。另外,我正在 Xamarin 开发移动应用程序。获得了 JSON.Net 的最新 NuGet 包。调用 JsonConvert.DeserializeObject(list2.First().Value.ToString()); 时没有出现同样的错误,这很奇怪。还有什么想法吗?我在我的问题中添加了一些额外的代码
    • 哦,好吧,我从没想过:)。我已经更新了我的答案以添加对自定义转换器的解释。它可以帮助您完成您正在尝试做的事情,无论是使用您的 JSON.net 版本,还是帮助保持初始化所有对象类型更易于管理。您是否可以尝试与通用 Windows 控制台应用程序或其他东西相同的代码?只是想看看 Xamarin 是否有什么奇怪的地方。
    • 您的编辑看起来很有希望。谢谢!明天我会进一步调查。我正在构建一个移动 json 缓存系统,因此我需要某种形式的模块化,因为我需要能够存储多种类型。我将尝试找到一种方法来稍微调整您的方法。有什么建议吗?
    • 哦,好的,我正在处理一些已知的时间,但在初始化它们时有各种细微差别(例如,在我反序列化所有内容后,我在 ReadJson 中做了一些设置)。如果您需要它来处理大量类型,那么自定义转换器可能不适合您 - 但是我到目前为止是它的专家。我刚刚尝试了您的 T Get(string key) 方法,它对我来说也很好用。当“错误设置值设置为'ReadabilityEnabled”异常被抛出时,你能看看并发布你得到的innerException吗?他们很可能会指出真正的原因。
    【解决方案2】:

    设法解决它。示例代码没有显示 ReadabilitySettings 也实现了 INotifyPropertyChanged 接口。随后的事件处理程序连接到项目中其他地方的 ReadabilitySettings 的 PropertyChanged 事件有一些错误,因此反序列化器无法实例化 ReadabilitySettings :-)。

    不是一个迷人的保存,但它的工作...感谢您的时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-21
      • 2023-03-12
      • 2019-08-27
      • 2014-08-22
      • 1970-01-01
      • 1970-01-01
      • 2021-05-26
      相关资源
      最近更新 更多