微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Newtonsoft JsonConvert vs System.Web.Helpers Json - 类型转换问题

如何解决Newtonsoft JsonConvert vs System.Web.Helpers Json - 类型转换问题

我一直在使用 System.Web.Helpers.Json 非常成功地反序列化对象,直到我收到一个 json,其中的键仅在字母的情况下不同,并且 Decode() 方法抛出一个 ArgumentException。我试图弄清楚如何让这个类以区分大小写的方式工作,但不能,所以我决定改用 Newtonsoft 库。 Json.NET 可以正常工作,但它返回的反序列化对象需要如下类型转换:

[TestMethod]
public void CaseSensitivitytest() {
  string json = "{\"e\":\"executionReport\",\"E\":1616877261436}";
  dynamic result = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
  string executionReport = result.e;//have to assign to a typed variable for the assert below to work
  Assert.AreEqual("executionReport",executionReport);
  Assert.IsTrue(1616877261436 == (long)result.E);//or explicitly cast to a type
  result = System.Web.Helpers.Json.Decode(json);//System.ArgumentException: An item with the same key has already been added.
  Assert.IsTrue(1616877261436 == result.E);//this would've worked without any type cast as in the example below
}

我的其余代码在很大程度上依赖于具有正确类型属性的反序列化对象(例如,我的典型代码 decimal.Parse(deserializedResponse.price) 期望 price 是字符串而不是 JValue<string>)。这是另一个比较:

[TestMethod]
public void TypeCasttest() {
  string json = "{\"intValue\":123}";
  dynamic webHelpersResult = System.Web.Helpers.Json.Decode(json);
  dynamic newtonSoftResult = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
  Assert.AreEqual(123,webHelpersResult.intValue);//All good here,I want JsonConvert to work the same way
  Assert.AreEqual(123,newtonSoftResult.intValue);//Assert.AreEqual Failed. Expected:<123 (system.int32)>. Actual:<123 (Newtonsoft.Json.Linq.JValue)>.
}

重构在任何地方添加类型转换是非常困难的,所以我更喜欢单点修复。我需要使 System.Web.Helpers.Json 区分大小写或 Newtonsoft.Json.JsonConvert 返回 .NET 类型的值而不是 JValue 类型。实现这一目标的最佳方法是什么?我正在编写一个在 Windows 7 机器上运行的控制台应用程序,所以所有花哨的 web/WINRT/Xamarin/等东西并不总是可用。

更新 反序列化为 ExpandoObject 的建议如下:

dynamic newtonSoftResult = JsonConvert.DeserializeObject<ExpandoObject>(json);

最初似乎可以工作,但是它无法反序列化 json 列表,而且我无法使其与 System.Web.Helpers.Json.Decode() 结果向后兼容:

string single = "{\"s\":\"String1\",\"f\":\"0.00\"}";
string multiple = "[{\"s\":\"String1\",\"f\":\"0.00\"},{\"s\":\"String2\",\"f\":\"1.23\"}]";
var helpeRSSingle = System.Web.Helpers.Json.Decode(single);
var helpersMultiple = System.Web.Helpers.Json.Decode(multiple);
var newtonSingle = Newtonsoft.Json.JsonConvert.DeserializeObject<ExpandoObject>(single);
var newtonMultiple = JsonConvert.DeserializeObject<ExpandoObject>(multiple);//system.invalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[System.Object]' to type 'System.Dynamic.ExpandoObject'.
Assert.AreEqual("String1",helpeRSSingle.s);
Assert.AreEqual("String2",helpersMultiple[1].s);
Assert.IsFalse(helpeRSSingle is IEnumerable);
Assert.IsFalse(newtonSingle is IEnumerable);//This fails as well as ExpandoObject would implement IEnumerable for its properties

解决方法

您可以将 Newtonsoft.Json 与以下助手类一起使用:

public static class JsonHelper
{
    public static object Deserialize(string json)
    {
        return ToObject(JToken.Parse(json));
    }

    private static object ToObject(JToken token)
    {
        switch (token.Type)
        {
            case JTokenType.Object:
                var expando = new ExpandoObject() as IDictionary<string,object>;
                foreach (JProperty prop in token.Children<JProperty>())
                {
                    expando.Add(prop.Name,ToObject(prop.Value));
                }
                return expando;

            case JTokenType.Array:
                return token.Select(ToObject).ToList();

            default:
                return ((JValue)token).Value;
        }
    }
}

在您的测试中,您可以:

dynamic result = JsonHelper.Deserialize(json);

结果将是 ExpandoObjectList<ExpandoObject>,它们应该适用于您的大多数测试。您必须对检查 IEnumerable 的测试进行调整,因为 ExpandoObject 确实实现了此接口。如果您需要区分单个对象或多个对象,则可以改为检查 IList

此处的工作示例:https://dotnetfiddle.net/n2jI1d

,

Newtonsoft 包装了 JSON 属性......出于各种我不会讨论的很好的理由。您不需要强制转换,您可以使用 .ValuenewtonSoft.intValue.Value。我应该指出,您仍然在使用动态类型解析整个 JSON 字符串,因为您没有使用其中的大部分内容并不是使用动态类型的好借口。我强烈建议您不要使用动态类型,而是使用动态类型。

[TestMethod]
public void TypeCastTest() {
  string json = "{\"intValue\":123}";
  dynamic webHelpersResult = System.Web.Helpers.Json.Decode(json);
  dynamic newtonSoftResult = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
  Assert.AreEqual(123,webHelpersResult.intValue);
  Assert.AreEqual(123,newtonSoftResult.intValue.Value);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。