问题
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. :)
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.
回答1:
There's no need for the long function in Charles'/your answer. Just use the generic ToObject
function and use the object
type parameter.
Complete Example:
using System;
using Newtonsoft.Json.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
string input = "Hello, world!";
JToken token = JToken.FromObject(input);
object output = token.ToObject<object>();
Console.WriteLine(output);
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
That said, you should know what type it is, and I can't really think of a situation where you wouldn't know what type it is and can't convert it to something more appropriate with a more specific type parameter in the call to ToObject
.
回答2:
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>();
}
}
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));
}
Input type: JArray
of Newtonsoft.Json.Linq.JValue
with JTokenType
of Integer
Output: List<object>
where each object is of type System.Int64
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.
Edit: 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.
来源:https://stackoverflow.com/questions/36659560/convert-json-net-objects-to-conventional-net-objects-without-knowing-the-types