我很难重写自定义 JsonConverter 的 WriteJson 方法,以便稍微改变执行序列化的方式。
我需要调用一个 REST 服务来接受具有通用部分的特定输入。我可以使用以下有效负载格式重现我遇到的问题:
public sealed class JsonField
{
public string Key { get; set; }
public object Value { get; set; }
public string OtherParam { get; set; }
}
public sealed class JsonPayload
{
public string Item1 { get; set; }
public string Item2 { get; set; }
public List<JsonField> Fields { get; set; }
}
我正在调用的 REST API 需要让 Fields 成为一个对象,其中包含尽可能多的字段,这些字段的名称与原始集合中指定的 Key 属性相对应。像这样:
{
"Item1" : "Value1",
"Item2" : "Value2",
...
"Fields":
{
"Key1": {"Value":"Value1", "OtherParam":"other1"}
"Key2": {"Value":42, "OtherParam":"other2"}
}
}
但是,使用默认选项,有效载荷是这样序列化的:
{
"Item1" : "Value1",
"Item2" : "Value2",
...
"Fields":[
{ "Key":"Key1", "Value":"Value1", "OtherParam":"other1" }
{ "Key":"Key2", "Value":42, "OtherParam":"other2" }
]
}
您注意到有一个对象集合,而我想要一个对象。 另外,我希望键名称是字段中各个属性的名称。
我很难搞清楚如何在我的自定义转换器中使用 JToken、JProperty、JValue 对象。事实上,我从来没有尝试过这样的事情,所以我发现很难理解这些概念。
我尝试创建两个自定义转换器,一个在类的范围内,以防止生成集合,第二个在集合的范围内,但到目前为止没有成功。
这是我尝试过的:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var token = JToken.FromObject(value);
var key = token["Key"];
if (key == null)
throw new Exception("missing key");
var propertyName = key.ToString();
var json = new StringBuilder();
json.Append("{");
foreach (var child in token.Children())
{
var property = child as JProperty;
if (property == null || property.Name == "Key")
continue;
var propName = property.Name;
var propValue = JsonConvert.SerializeObject(property.Value);
json.AppendFormat("\"{0}\": {1},", propName, propValue);
}
if (json.Length > 1)
json.Remove(json.Length - 1, 1);
json.Append("}");
var newToken = JToken.Parse(json.ToString());
var serializedObject = JsonConvert.SerializeObject(newToken);
writer.WriteStartObject();
writer.WritePropertyName(propertyName);
writer.WriteToken(newToken.CreateReader());
writer.WriteEndObject();
}
有没有办法实现我想要实现的目标?
也许我以错误的方式解决了这个问题,所以如果您有更简单的替代方案,请务必毫不犹豫地分享您的想法。
最佳答案
您走在正确的轨道上。您在这里只需要一个转换器——用于 JsonField
对象的列表——而且代码实际上非常简单。这就是您所需要的:
class JsonFieldListConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(List<JsonField>));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject containerObj = new JObject();
foreach (JsonField field in (List<JsonField>)value)
{
JObject itemObj = new JObject();
itemObj.Add("Value", JToken.FromObject(field.Value));
itemObj.Add("OtherParam", new JValue(field.OtherParam));
containerObj.Add(field.Key, itemObj);
}
containerObj.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
这是一个展示转换器运行的演示:
class Program
{
static void Main(string[] args)
{
JsonPayload payload = new JsonPayload
{
Item1 = "Value1",
Item2 = "Value2",
Fields = new List<JsonField>
{
new JsonField { Key = "Key1", Value = "Value1", OtherParam = "other1" },
new JsonField { Key = "Key2", Value = 42, OtherParam = "other2" },
}
};
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new JsonFieldListConverter());
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(payload, settings);
Console.WriteLine(json);
}
}
输出:
{
"Item1": "Value1",
"Item2": "Value2",
"Fields": {
"Key1": {
"Value": "Value1",
"OtherParam": "other1"
},
"Key2": {
"Value": 42,
"OtherParam": "other2"
}
}
}
关于c# - 使用自定义 JsonConverter 来改变对象部分的序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22230440/