CanConvert
nie zostanie wywołany, gdy oznaczysz coś za pomocą [JsonConverter]
. Kiedy używasz tego atrybutu, Json.Net zakłada, że podałeś poprawny konwerter, więc nie przejmuje się sprawdzaniem CanConvert
. Jeśli usuniesz atrybut, zostanie on wywołany na podstawie przekazania instancji konwertera do ustawień. To, co widzisz, to Json.Net testujący twój konwerter dla wszystkich innych typów nieruchomości.
EDIT
ułożyła szybki fiddle aby pokazać o co mi chodzi (kod jest również przedstawione poniżej dla kompletności).
bez zmian programu CanConvert()
jest wywoływana na FooConverter
dla wszystkich typów wyjątkiemFoo
, a mimo to nadal przetwarza Foo
poprawnie.
Jeśli wykomentuj atrybut [JsonConverter]
na nieruchomości Wrapper.Foo
, można zobaczyć, że CanConvert()
będzie teraz sprawdzony na typ Foo
mocy FooConverter
wchodzących w JsonSerializerSettings
.
Jeśli zamiast zakomentuj linię Main
gdzie FooConverter
jest dodawana do ustawień, a następnie CanConvert
nigdy nie jest nazywany dla każdego typu, jeszcze Foo
nadal poprawnie konwertowane z powodu atrybutu [JsonConverter]
stosowanej do nieruchomości Foo
w Wrapper
klasa.
Tak więc na wynos jest to, że istnieją dwa mechanizmy wskazujące, czy konwerter powinien być używany, i nie potrzebujesz obu. Możesz zastosować atrybut, który powie Json.Net, że konkretny konwerter powinien być używany dla określonej właściwości (lub klasy) i nie musi najpierw pytać konwertera. Alternatywnie możesz dodać konwerter do ustawień, w takim przypadku Json.Net musi zapytać każdego konwertera, czy może obsłużyć każdy typ. Ten pierwszy jest nieco bardziej wydajny, a drugi jest przydatny w sytuacjach, gdy nie posiadasz kodu źródłowego klasy, którą próbujesz przekonwertować. Mam nadzieję, że to ma sens.
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();
}
}
}
modyfikator klasy jest publiczny? – codebased
Tak, zarówno encja, jak i konwerter są publiczne. – ilivewithian