9
votes

JSON.NET peut-il peupler des champs réadonnément dans une classe?

Je n'ai pas vu beaucoup d'informations sur json.net prenant en charge des objets désérialisants avec lisonly champs. Je remarque que les attributs de Datacontract et de DataMember DataContract et Datammember permettent de remplir des champs lisonly lors de la désérioriztion, mais JSON.net ne semble pas supporter cela, du moins du comportement que je vois.


0 commentaires

3 Réponses :


-2
votes

Afai peut voir la modification d'un champ sur Readonly CODE> Résultats dans un NULL code> Valeur après la désérialisation. J'ai eu un échantillon de travail pour une autre question (modifié comme indiqué ci-dessous), et c'est le comportement que je vois.

public class NameAndId
{
    public string name;
    public int id; 
}

public class Data
{
    public NameAndId[] data;
}

public class Target
{
    public string id;
    public readonly NameAndId from;
    public DateTime updated_time;
    public readonly string message;
    public Data likes;
}

public class Program
{
    static void Main(string[] args)
    {
        string json = File.ReadAllText(@"c:\temp\json.txt");
        Target newTarget = JsonConvert.DeserializeObject<Target>(json);
    }
}


4 commentaires

Oui, c'est le même comportement que je vois. Malheureusement, cela avec des restrictions de constructeur sur les objets sérialisés est le disjoncteur de l'accord pour JSON.NET pour moi. :(


Je suppose que les classes intégrées .NET ont un accès privilégié à ces domaines qui ne sont pas disponibles pour la bibliothèque tierce.


Ce n'est pas différent de définir tout autre champ avec une réflexion, de sorte que c'est faisable et j'ai déposé une demande de fonctionnalité sur le tracker json.net.


@MarkLemoine Il y a actuellement - à ma connaissance - aucune restriction CTOR que vous ne pouvez pas me contenter de créer un résolveur de contrat personnalisé.



10
votes

Pas la solution la plus élégante, mais vous pouvez étendre la valeur par défautConstractResolver pour le faire:

public class ContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        property.Writable = CanSetMemberValue(member, true);
        return property;
    }

    public static bool CanSetMemberValue(MemberInfo member, bool nonPublic)
    {
        switch (member.MemberType)
        {
            case MemberTypes.Field:
                var fieldInfo = (FieldInfo)member;

                return nonPublic || fieldInfo.IsPublic;
            case MemberTypes.Property:
                var propertyInfo = (PropertyInfo)member;

                if (!propertyInfo.CanWrite)
                    return false;
                if (nonPublic)
                    return true;
                return (propertyInfo.GetSetMethod(nonPublic) != null);
            default:
                return false;
        }
    }
}


0 commentaires

5
votes

Cela peut être fait maintenant. Déclarez vos propriétés à l'aide de l'attribut JSONPROPERTY et assurez-vous qu'ils ont un ensemble protégé déclaré: xxx

Cela n'a pas fonctionné pour moi lors de l'utilisation d'un Obtenez , mais fonctionne parfaitement avec l'ensemble protégé .


2 commentaires

L'attribut [jsonproperty] n'est pas requis pour que cela fonctionne


Cela n'a pas fonctionné pour moi aucune autre voie en 2017. Et j'ai essayé pratiquement toutes les combinaisons que je pouvais trouver. J'écris un générateur de code, j'ai donc passé beaucoup de temps à rendre le code généré aussi serré que possible. Mais cela peut certainement avoir été changé au cours des deux dernières années.