在不知道类型的情况下将Json.NET对象转换为常规.NET对象

在不知道类型的情况下将Json.NET对象转换为常规.NET对象

问题描述:

如何将Json.NET对象转换为常规.NET类型(JArray of stringList<string>JTokenType=Integerint等)? 除了使用AutoMapperJToken.ToObject<T>的建议外,我几乎没有发现其他建议. 当在编译时知道JSON结构时,这是一个很好的建议,但是当我不知道基础类型时,我无法创建一个表示未知数据的类,也不能指定转换. Json.NET没有"ConvertToWhateverIsProbablyMostAppropriate()"成员. :)

How do I convert Json.NET objects to conventional .NET types (JArray of string to List<string>, JTokenType=Integer to int, etc.)? I have found little besides suggestions to use AutoMapper or JToken.ToObject<T>. This is good advice when the JSON structure is known at compile time, but I can't create a class to represent unknown data, or specify a conversion when I don't know the underlying type. Json.NET doesn't have a "ConvertToWhateverIsProbablyMostAppropriate()" member. :)

那么为什么不仅仅枚举JWhatever对象,而将它们保持原样呢? 因为我无法将这些类型作为参数传递给(例如)Dapper,Dapper并不从 spoo .

So why not just enumerate through JWhatever objects, leaving them as-is? Because I can't pass those types as parameters to (say) Dapper, which doesn't know JToken from spoo.

我编写了以下方法,将JToken转换为旧的传统.NET类型. 这比我需要的要彻底(仅处理少数几个JTokenType),但是我将其扩展了此答案.

I wrote the following method to convert JToken to good old conventional .NET types. This is more thorough than I need (to handle only a few JTokenTypes), but I extended it for this answer.

注意事项:该代码未经测试,可能无法解决不存在的问题.这是最糟糕的方法的错误实现.

Caveat discipulus: This code is untested and may be a poor implementation of the worst possible approach to a problem that doesn't exist.

    /// <summary>Converts a Json.Net JToken to a boxed conventional .NET type (int, List, etc.)</summary>
    /// <param name="token">The JToken to evaluate</param>
    public object JTokenToConventionalDotNetObject(JToken token)
    {
        switch(token.Type) {
            case JTokenType.Object:
            return ((JObject)token).Properties()
                .ToDictionary(prop => prop.Name, prop => JTokenToConventionalDotNetObject(prop.Value));
            case JTokenType.Array:
            return token.Values().Select(JTokenToConventionalDotNetObject).ToList();
            default:
            return token.ToObject<object>();
        }
    }

要处理JArrays,这是我最初遇到的问题,Json.NET再次使任务变得简单:

To handle JArrays, my original problem, Json.NET again makes the task simple:

    /// <summary>Converts a Json.NET JArray into a List of T where T is a conventional .NET type (int, string, etc.)</summary>
    /// <param name="jArray">Json.NET JArray to convert</param>
    public IList<object> JArrayToList(JArray jArray) {
        return (List<object>)jArray.ToObject(typeof(IList));
    }

输入类型:Newtonsoft.Json.Linq.JValueJArrayIntegerJTokenType

输出:List<object>其中每个对象的类型为System.Int64

Output: List<object> where each object is of type System.Int64

我相信Json.NET的ToObject行为并不总是很明显.给定转换类型<Object>,它要么返回常规的.NET类型(longstring),要么什么都不做,例如获取并返回Newtonsoft.Json.Linq.JArray,具体取决于JTokenType.

I believe that Json.NET's ToObject behavior is not always obvious. Given conversion type <Object>, it returns either a conventional .NET type (long, string) or does nothing at all, e.g. gets and returns Newtonsoft.Json.Linq.JArray, depending on the JTokenType.

在@mason的帮助下以及带有SO问题的代码(其地雷被标记为重复)的简化代码.现在,我更好地了解了Json.NET的类型工作原理,我发现答案就足够了.

Simplified code with @mason's help and with code from the SO question for which mine is marked duplicate. Now that I better understand Json.NET's types work, I see that answer was sufficient.

答案之间的显着区别只是该代码处理嵌套的数组/对象.

The salient difference between the answers is only that that this code handles nested arrays/objects.