Je sais qu'il existe un attribut pour gérer les setters privés, mais je veux un peu ce comportement par défaut, y a-t-il un moyen d'accomplir cela? Sauf en modifiant la source. Ce serait génial s'il y avait un cadre pour cela.
Réponses:
Je suis venu ici à la recherche de l'attribut réel qui fait que Json.NET remplit une propriété en lecture seule lors de la désérialisation, et c'est simplement [JsonProperty], par exemple:
[JsonProperty]
public Guid? ClientId { get; private set; }
Fournissez simplement un constructeur qui a un paramètre correspondant à votre propriété:
public class Foo
{
public string Bar { get; }
public Foo(string bar)
{
Bar = bar;
}
}
Maintenant cela fonctionne:
string json = "{ \"bar\": \"Stack Overflow\" }";
var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow
Je préfère cette approche dans la mesure du possible car:
{ get; private set; }et juste { get; }.{get;private set;}, pas avec{get;}
{ get; }si le type a un constructeur avec un paramètre correspondant au nom de la propriété.
J'ai écrit une distribution source NuGet pour cela, qui installe un seul fichier avec deux résolveurs de contrat personnalisés:
Installez le NuGet:
Install-Package JsonNet.PrivateSettersContractResolvers.Source
Ensuite, utilisez simplement l'un des résolveurs:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
Vous pouvez en savoir plus ici: http://danielwertheim.se/json-net-private-setters-nuget/
Repo GitHub: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers
Il existe deux alternatives qui peuvent résoudre le problème.
Alt 1: sur les désérialiseurs
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
L'option de sérialisation par défaut prend en charge tous les types de membres de classe. Par conséquent, cette solution renverra tous les types de membres privés, y compris les champs. Je suis seulement intéressé à soutenir également les setters privés.
Alt2: Créez un ContractResolver personnalisé:
Par conséquent, ce sont les meilleures options puisque nous vérifions simplement les propriétés.
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;
}
}
Pour plus d'informations, lisez mon article: http://danielwertheim.se/json-net-private-setters/
DefaultMembersSearchFlagsest obsolète .
{get; }n'est PAS équivalent à { get; private set; }. Pour la première manière property.GetSetMethod(true)revient nullet la seconde true. Cela m'a surpris. Vous devez avoir private set;pour que la désérialisation fonctionne comme prévu.
La réponse de @ Daniel (Alt2) est parfaite, mais j'en avais besoin pour fonctionner à la fois pour les setters privés et les getters (je travaille avec une API qui contient en fait quelques éléments en écriture seule, comme user.password.) Voici ce que j'ai obtenu:
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;
}
}
Enregistré ainsi:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
ContractResolver = new NonPublicPropertiesResolver()
};