如何在JSON中定义字符串到对象/字典

时间:2018-04-11 05:06:53

标签: c# json

我创建了一个用于定义我的请求的类,我没有获得接受的JSON字符串

我定义了这个对象:

public class Request
{
    public Var_Args[] var_args { get; set; }
}

public class  Var_Args
{
    public object title { get; set; }
    public object owner { get; set; }
}

当我将其转换为json时,我得到以下字符串:

{"requests":[{"var_args":[{"title":"Test","owner":"skaner"}]}]}

如何定义类,以获取接受的json字符串:

{"requests":[{"var_args":[{"title":"Test"},{"owner":"skaner"}]}]}

3 个答案:

答案 0 :(得分:2)

您可以编写一个自定义JSON转换器,它可以将对象(已知类型的)的每个属性序列化为不同的JSON对象。

public class PropertyAsObjectConverter : JsonConverter
{
   private readonly Type[] _types;

   public PropertyAsObjectConverter(params Type[] types)
   {
      _types = types;
   }

   public override bool CanConvert(Type objectType)
   {
      return _types.Any(t => t == objectType);
   }

   public override bool CanRead
   {
      get { return false; }
   }

   public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
   {
      throw new NotImplementedException();
   }

   public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
   {
      var properties = value.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance);
      foreach(var property in properties)
      {
         var name = property.Name;
         var attrs = property.GetCustomAttributes(typeof(JsonPropertyAttribute));
         if(attrs != null)
         {
            if (attrs.FirstOrDefault() is JsonPropertyAttribute attr)
               name = attr.PropertyName;
         }

         writer.WriteStartObject();
         writer.WritePropertyName(name);
         serializer.Serialize(writer, property.GetValue(value));
         writer.WriteEndObject();
      }
   }
}

这只实现序列化,但您也可以扩展它以支持反序列化。如果需要,您还可以将其扩展为序列化字段。

然后,您可以按如下方式定义类。请注意,我在这里使用JsonPropertyAttribute来指定序列化JSON中的名称。

public class Content
{
   [JsonProperty("requests")]
   public Request Value { get; set; }
}

public class Request
{
   [JsonProperty("var_args")]
   public VarArgs[] Arguments { get; set; }
}

public class VarArgs
{
   [JsonProperty("title")]
   public object Title { get; set; }

   [JsonProperty("owner")]
   public object Owner { get; set; }
}

您可以使用它:

static void Main(string[] args)
{
   var request = new Content()
   {
      Value = new Request()
      {
         Arguments = new VarArgs[]
         {
            new VarArgs()
            {
               Title = "Test",
               Owner = "Skaner",
            }
         }
      }
   };

   var text = JsonConvert.SerializeObject(
      request,
      Formatting.None, 
      new PropertyAsObjectConverter(typeof(VarArgs)));

   Console.WriteLine(text);
}

此示例的输出是您期望的输出:

{"requests":{"var_args":[{"title":"Test"},{"owner":"Skaner"}]}}

答案 1 :(得分:0)

您可以使用下面的custom JsonConverter。 它接受Var_Args对象并将其拆分为两个不同的JObject,它们对应于两个不同的JSON对象。

public class VarArgsConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var obj = (JObject)JToken.FromObject(value);

        var objTitle = new JObject();
        objTitle.Add("title", obj.GetValue("title"));

        var objOwner = new JObject();
        objOwner.Add("owner", obj.GetValue("owner"));

        objTitle.WriteTo(writer);
        objOwner.WriteTo(writer);
    }


    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Var_Args);
    }
}

public class Wrapper
{
    [JsonProperty("requests")]
    public Request Requests { get; set; }
}

public class Request
{
    public Var_Args[] var_args { get; set; }
}

public class Var_Args
{
    public object title { get; set; }
    public object owner { get; set; }
}

然后使用它:

var wrapper = new Wrapper();

var request = new Request();
request.var_args = new Var_Args[] {
    new Var_Args(){ title = "Test", owner = "skaner" },
    new Var_Args(){ title = "Test2", owner = "skaner2" }
};

wrapper.Requests = request;

var serialized = JsonConvert.SerializeObject(wrapper, new VarArgsConverter());

<强>输出

{"requests":{"var_args":[{"title":"Test"},{"owner":"skaner"},{"title":"Test2"},{"owner":"skaner2"}]}}

注意:我正在使用Wrapper类来生成请求的JSON。

如果您不想每次都指定转换器,则可以全局注册转换器。请参阅this answer,其中说明了如何执行此操作。因此,每次尝试序列化JsonConverter对象时,序列化程序都会使用您的自定义Var_Args

如果您在全局注册JsonConvert,则可以使用:

var serialized = JsonConvert.SerializeObject(wrapper);

答案 2 :(得分:0)

您可以使用modelBuilder.Entity<Geofence>() .HasMany(e => e.Coordinates) .WithOne() .OnDelete(DeleteBehavior.Cascade); 重新定义System.Reflection作为Var_Args接口的实现,方法是向该类添加两个方法:

IEnumerable<Dictionary<string,object>>

虽然public class Var_Args : IEnumerable<Dictionary<string,object>> { IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public IEnumerator<Dictionary<string,object>> GetEnumerator() { var Properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var Property in Properties) { var Entry = new Dictionary<string,object>(); Entry.Add(Property.Name, Property.GetValue(this)); yield return Entry; } } public object title { get; set; } public object owner { get; set; } } 可能被认为很慢,但是有一种技术可以用来在运行时静态编译Reflection,这样反射只会出现一次类的定义,如下所示:

IEnumerable