CanConvert
non viene chiamato quando si contrassegna qualcosa con [JsonConverter]
. Quando si utilizza l'attributo, Json.Net presuppone che sia stato fornito il convertitore corretto, quindi non si preoccupa del controllo CanConvert
. Se rimuovi l'attributo, verrà richiamato in virtù del passaggio dell'istanza del convertitore alle impostazioni. Quello che stai vedendo è Json.Net testare il tuo convertitore per tutti gli altri tipi di proprietà.
EDIT
Ho messo insieme un rapido fiddle per mostrare quello che voglio dire (il codice è anche riprodotto qui di seguito per completezza).
senza modifiche al programma, CanConvert()
viene chiamato sul FooConverter
per tutti i tipi tranneFoo
, eppure converte ancora Foo
correttamente.
Se si commento fuori l'attributo [JsonConverter]
sulla proprietà Wrapper.Foo
, si può vedere che CanConvert()
avrà ora chiamato per il tipo Foo
in virtù della FooConverter
essere inclusi nella JsonSerializerSettings
.
Se invece commentare la linea in Main
in cui viene aggiunto alle impostazioni della FooConverter
, poi CanConvert
non viene mai chiamato per qualsiasi tipo, ma Foo
è ancora convertito correttamente a causa l'attributo [JsonConverter]
applicata alla proprietà Foo
nel Wrapper
classe.
Quindi il takeaway qui è che ci sono due meccanismi per indicare se un convertitore dovrebbe essere usato, e non è necessario entrambi. È possibile applicare un attributo e questo dirà a Json.Net che un particolare convertitore deve essere utilizzato per una particolare proprietà (o classe) e non è necessario chiedere prima al convertitore. In alternativa, è possibile aggiungere il convertitore alle impostazioni, nel qual caso Json.Net deve chiedere a ciascun convertitore se può gestire ciascun tipo. Il primo è un po 'più efficiente, mentre il secondo è utile in situazioni in cui non si possiede il codice sorgente per la classe che si sta tentando di convertire. Spero che questo abbia un senso.
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();
}
}
}
Il modificatore di classe è pubblico? – codebased
Sì, sia l'entità che il convertitore sono pubblici. – ilivewithian