我有一个自定义JsonConverter
,似乎无法正确调用。我创建了转换器,将其添加到JsonSerializerSettings.Converters
集合并在我使用[JsonConverter(typeof(SearchGeoConverter))]
序列化的实体上标记了属性,但即使使用这些转换器,转换器CanConvert
方法也看不到我试图转换的类型。我只看到string
,int
和JObject
。
我的转换器看起来像这样:
public class SearchGeoConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(DbGeography).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var point = (DbGeography) value;
var rawJson = string.Format("{{ \"type\": \"Point\", \"coordinates\": [{0}, {1}] }}", point.Latitude, point.Longitude);
writer.WriteRaw(rawJson);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
我错过了什么?
答案 0 :(得分:14)
CanConvert
标记内容时, [JsonConverter]
不会被调用。当您使用该属性时,Json.Net假定您提供了正确的转换器,因此它不会对CanConvert
检查感到烦恼。如果删除该属性,则会通过将转换器实例传递给设置来调用它。您所看到的是Json.Net针对所有其他属性类型测试您的转换器。
修改强>
我快速组合fiddle来表明我的意思(代码也在下面转载完整性)。
如果没有对程序进行任何更改,CanConvert()
会针对除 FooConverter
之外的所有类型调用Foo
,但它仍会正确转换Foo
如果您在[JsonConverter]
属性上注释掉Wrapper.Foo
属性,则可以看到CanConvert()
现在将因类型Foo
而被调用FooConverter
被包含在JsonSerializerSettings
。
如果您注释掉Main
中FooConverter
添加到设置中的行,则永远不会为任何类型调用CanConvert
,但Foo
仍然是[JsonConverter]
由于Foo
属性应用于Wrapper
类中的using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
public class Program
{
public static void Main()
{
JsonSerializerSettings settings = new JsonSerializerSettings();
// Comment out the following line and CanConvert() never gets called on
// FooConverter for any type yet the FooConverter is still working due
// to the JsonConverter attribute applied to Wrapper.Foo
settings.Converters.Add(new FooConverter());
settings.Converters.Add(new BarConverter());
settings.Formatting = Formatting.Indented;
Wrapper w = new Wrapper
{
Foo = new Foo
{
A = "bada",
B = "boom",
},
Bar = new Bar
{
C = "bada",
D = "bing"
}
};
string json = JsonConvert.SerializeObject(w, settings);
Console.WriteLine(json);
}
class Wrapper
{
// Comment out this attribute and CanConvert will be called on FooConverter
// for type Foo due to the fact that the FooConverter has been added to the
// JsonSerializerSettings
[JsonConverter(typeof(FooConverter))]
public Foo Foo { get; set; }
public Bar Bar { get; set; }
}
class Foo
{
public string A { get; set; }
public string B { get; set; }
}
class Bar
{
public string C { get; set; }
public string D { get; set; }
}
class FooConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
bool result = typeof(Foo).IsAssignableFrom(objectType);
Console.WriteLine("FooConverter CanConvert() called for type " +
objectType.Name + " (result = " + result + ")");
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var foo = (Foo) value;
JObject jo = new JObject();
jo.Add("AplusB", new JValue(foo.A + " " + foo.B));
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
class BarConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
bool result = typeof(Bar).IsAssignableFrom(objectType);
Console.WriteLine("BarConverter CanConvert() called for type " +
objectType.Name + " (result = " + result + ")");
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var bar = (Bar) value;
JObject jo = new JObject();
jo.Add("CplusD", new JValue(bar.C + " " + bar.D));
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
}
属性而正确转换。
所以这里要说的是,有两种机制可以指示是否应该使用转换器,而且不需要两者。您可以应用一个属性,这将告诉Json.Net特定转换器应该用于特定属性(或类),并且它不需要首先询问转换器。或者,您可以将转换器添加到设置中,在这种情况下,Json.Net必须询问每个转换器是否可以处理每种类型。前者效率更高,而后者在您不拥有要转换的类的源代码的情况下非常有用。希望这是有道理的。
{{1}}