So che esiste un attributo per gestire i setter privati, ma voglio che questo comportamento sia predefinito, c'è un modo per farlo? Tranne modificare la fonte. Sarebbe fantastico se ci fosse un ambiente per questo.
Risposte:
Sono venuto qui alla ricerca dell'attributo effettivo che fa sì che Json.NET popoli una proprietà di sola lettura durante la deserializzazione, e questo è semplicemente [JsonProperty]
, ad esempio:
[JsonProperty]
public Guid? ClientId { get; private set; }
Fornisci semplicemente un costruttore che abbia un parametro che corrisponde alla tua proprietà:
public class Foo
{
public string Bar { get; }
public Foo(string bar)
{
Bar = bar;
}
}
Ora funziona:
string json = "{ \"bar\": \"Stack Overflow\" }";
var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow
Preferisco questo approccio ove possibile poiché:
{ get; private set; }
e solo { get; }
.{get;private set;}
, non con{get;}
{ get; }
se il tipo ha un costruttore con un parametro che corrisponde al nome della proprietà.
Ho scritto una distribuzione di origine NuGet per questo, che installa un singolo file con due risolutori di contratto personalizzati:
Installa NuGet:
Install-Package JsonNet.PrivateSettersContractResolvers.Source
Quindi usa uno dei resolver:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
Puoi leggerlo qui: http://danielwertheim.se/json-net-private-setters-nuget/
Repo GitHub: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers
Esistono due alternative che possono risolvere il problema.
Alt 1: sui deserializzatori
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
L'opzione di serializzazione predefinita supporta tutti i tipi di membri della classe. Pertanto questa soluzione restituirà tutti i tipi di membri privati inclusi i campi. Mi interessa solo supportare anche i setter privati.
Alt2: crea un ContractResolver personalizzato:
Pertanto questa è l'opzione migliore poiché controlliamo solo le proprietà.
public class SisoJsonDefaultContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
//TODO: Maybe cache
var prop = base.CreateProperty(member, memberSerialization);
if (!prop.Writable)
{
var property = member as PropertyInfo;
if (property != null)
{
var hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
}
}
return prop;
}
}
Per ulteriori informazioni, leggi il mio post: http://danielwertheim.se/json-net-private-setters/
DefaultMembersSearchFlags
è stato deprecato .
{get; }
NON è equivalente a { get; private set; }
. Per il primo modo property.GetSetMethod(true)
ritorna null
e per il secondo true
. Questo mi ha sorpreso. È necessario disporre di private set;
affinché la deserializzazione funzioni come previsto.
La risposta di @ Daniel (Alt2) è perfetta, ma avevo bisogno che funzionasse sia per i setter privati che per i getter (sto lavorando con un'API che in realtà ha alcune cose di sola scrittura, come user.password
.) Ecco cosa ho finito con:
public class NonPublicPropertiesResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
var prop = base.CreateProperty(member, memberSerialization);
if (member is PropertyInfo pi) {
prop.Readable = (pi.GetMethod != null);
prop.Writable = (pi.SetMethod != null);
}
return prop;
}
}
Registrato così:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
ContractResolver = new NonPublicPropertiesResolver()
};