2

例如,我有一些课程:

  class User 
  {
       int Id {get; set;}
       string Name {get; set;}
  }

  class Venue
  {
       int Id {get; set;}
       string Adress {get; set;}
  } 

  class Message
  {
     string Text {get; set;}
     int FromId {get; set;}
  }

我从网上获取 json:

  [%user% => {id: 1, name: "Alex"}, %user% => {id: 5, name: "John"}]

我可以解析它:

var myObjects = JsonConvert.DeserializeObject<Dictionary<string, User>>(json);

但是如果有一个json:

  [%user% => {id: 1, name: "Alex"}, %venue% => {id: 465, adress: "Thomas at 68th Street"}, %message% => {text: "hello", fromId: 78}]

我可以通过键 %user% = User、%venue% = Venue 等来定义类型。

但是我该如何解析呢?

提前致谢!

更新

我目前的解决方案:

 private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.All,
            TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
        };

 string myJson = "{\"%user%\":{\"id\" : 5, \"name\" : \"John\"}, \"%venue%\":{\"id\" : \"5f56de\", \"adress\": \"Thomas at 68th Street\"}}";

 Dictionary<string, object> dict = 
                JsonConvert.DeserializeObject<Dictionary<string, object>>
                (myJson, _jsonSettings);

 Dictionary<string, object> d = new Dictionary<string, object>();

 foreach(var o in dict)
 {
                string json =  (string)o.Value.ToString();

                switch (o.Key)
                {
                    case "%user%":
                        {
                            var v = JsonConvert.DeserializeObject<User>(json);
                            d.Add(o.Key, v);
                            break;
                        }

                    case "%venue%":
                        {
                            var v = JsonConvert.DeserializeObject<Venue>(json);
                            d.Add(o.Key, v);
                            break;
                        }
                    case "%message%":
                        {
                            var v = JsonConvert.DeserializeObject<Message>(json);
                            d.Add(o.Key, v);
                            break;
                        }
                }
   }
4

2 回答 2

2

如果您使用 Json.Net(又名 Newtonsoft.Json),您可以创建自定义 JsonConverter 对象。该对象将允许自定义解析 json。所以,给定以下类

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Venue
{
    public string Id { get; set; }
    public string Address { get; set; }
}

public class Message
{
    public string Text { get; set; }
    [JsonProperty("fromId")]
    public string FromId { get; set; }
}

您可以将它们包含在另一个分配有 JsonConverter 的类中

[JsonConverter(typeof(PostJsonConverter))]
public class Post
{
    public User User { get; set; }
    public Venue Venue { get; set; }
    public Message Message { get; set; }
}

JsonConvter 类是一个抽象类,您需要覆盖三个方法。您需要实现 ReadJson 方法。如果你不需要写json,那么就不需要在WriteJson方法中做任何事情。

public class PostJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // not implemented
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // it must be an object being passed in, if not something went wrong!
        if (reader.TokenType != JsonToken.StartObject) throw new InvalidOperationException();

        var postToken = JToken.ReadFrom(reader);
        var userToken = postToken["%user%"];
        var venueToken = postToken["%venue%"];
        var messageToken = postToken["%message%"];

        return new Post
        {
            User = userToken == null ? null : userToken.ToObject<User>(),
            Venue = venueToken == null ? null : venueToken.ToObject<Venue>(),
            Message = messageToken == null ? null : messageToken.ToObject<Message>(),
        };
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

不需要额外的工作来将其从正常转换中转换,因为我们已经为类提供了 JsonConverterAttribute。

string myJson = "{\"%user%\":{\"id\" : 5, \"name\" : \"John\"}, \"%venue%\":{\"id\" : \"5f56de\", \"address\": \"Thomas at 68th Street\"}}";
Post post = JsonConvert.DeserializeObject<Post>(myJson);
于 2013-09-27T06:20:36.333 回答
0

这是一个简洁的可能解决方案,使用我的小型 JSON 解析器库:

            public class User
            {
                    public int Id { get; set; }
                    public string Name { get; set; }
            }

            public class Venue
            {
                    public int Id { get; set; }
                    public string Address { get; set; }
            }

            public class Message
            {
                    public string Text { get; set; }
                    public int FromId { get; set; }
            }

            /* Deals with this SO question :
             * 
             * http://stackoverflow.com/questions/19023696/deserialize-dictionarystring-t
             */
            public static void SO_19023696()
            {
                    Console.Clear();
                    Console.WriteLine("StackOverflow question 19023696 - Polymorphic, key-driven Test");
                    Console.WriteLine();
                    string myJson = @"
        [
            {
              ""%user%"" : { ""id"": 1, ""name"": ""Alex""} ,
              ""%venue%"" : { ""id"": 465, ""address"": ""Thomas at 68th Street"" },
              ""%message%"" : { ""text"": ""hello"", ""fromId"": 78 }
            },
            {
              ""%user%"" : { ""id"": 2, ""name"": ""Carl""} ,
              ""%message%"" : { ""text"": ""bye"", ""fromId"": 79 }
            }
        ]";

                    Dictionary<string, object>[] parsed =
                            JSON.Map(null as Dictionary<string, object>[]).
                                    FromJson
                                    (
                                            myJson,
                                            JSON.Map(default(Dictionary<string, object>)).
                                                    Using // Deal with the main issue raised by the SO question:
                                                    (
                                                            (outer, type, value) =>
                                                                    ((outer.Hash != null) && outer.Hash.ContainsKey("Name") ? (Func<object>)
                                                                    (() => new User { Id = (int)outer.Hash["Id"], Name = (string)outer.Hash["Name"] }) :
                                                                            ((outer.Hash != null) && outer.Hash.ContainsKey("Address") ? (Func<object>)
                                                                            (() => new Venue { Id = (int)outer.Hash["Id"], Address = (string)outer.Hash["Address"] }) :
                                                                                    ((outer.Hash != null) && outer.Hash.ContainsKey("Text") ? (Func<object>)
                                                                                    (() => new Message { FromId = (int)outer.Hash["FromId"], Text = (string)outer.Hash["Text"] }) :
                                                                                            null
                                                                                    )
                                                                            )
                                                                    )
                                                    ),
                                            Sample_Revivers.CamelCaseToPascalCase,
                                            Sample_Revivers.DoubleToInteger
                                    );
                    System.Diagnostics.Debug.Assert(parsed[0]["%user%"] is User);
                    System.Diagnostics.Debug.Assert(parsed[0]["%venue%"] is Venue);
                    System.Diagnostics.Debug.Assert(parsed[0]["%message%"] is Message);
                    System.Diagnostics.Debug.Assert(parsed[1]["%user%"] is User);
                    System.Diagnostics.Debug.Assert(parsed[1]["%message%"] is Message);
                    Console.Write("Passed - Press a key...");
                    Console.ReadKey();
            }

可以在这里找到更多通过通用字典、匿名类型或 POCO 的用例/示例:

https://code.google.com/p/ysharp/source/browse/trunk/TestJSONParser/BasicTests.cs

于 2013-11-25T09:58:47.400 回答