Частные сеттеры в Json.Net


Я знаю, что есть атрибут для обработки частных сеттеров, но я хочу, чтобы это поведение было по умолчанию, есть ли способ сделать это? Кроме настройки источника. Было бы здорово, если бы была установка для этого.

3   51  

3 ответа:

Я пришел сюда в поисках фактического атрибута, который делает Json.NET заполните свойство readonly при десериализации, и это просто [JsonProperty], например:

[JsonProperty]
public Guid? ClientId { get; private set; }

Альтернативный Вариант

просто укажите конструктор, который имеет параметр, соответствующий вашему свойству:

public class Foo
{
    public string Bar { get; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}

теперь это работает:

string json = "{ \"bar\": \"Stack Overflow\" }";

var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow

Я предпочитаю этот подход, где это возможно, так как:

  • это не требует от вас, чтобы украсить свои свойства с атрибуты.
  • он работает с { get; private set; } и просто { get; }.

обновленный, новый ответ

Я написал исходный дистрибутив NuGet для этого, который устанавливает один файл с двумя пользовательскими преобразователями контрактов:

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamescontractresolver

установите NuGet:

Install-Package JsonNet.PrivateSettersContractResolvers.Source

тогда просто используйте любой из решателей:

var settings = new JsonSerializerSettings
{
    ContractResolver = new PrivateSetterContractResolver()
};

var model = JsonConvert.DeserializeObject<Model>(json, settings);

вы можете прочитать об этом здесь: http://danielwertheim.se/json-net-private-setters-nuget/

GitHub repo:https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers

старый ответ (все еще действителен)

есть две альтернативы, которые могут решить эту проблему.

АЛТ 1: на десериализаторы

ContractResolver.DefaultMembersSearchFlags =
                             DefaultMembersSearchFlags | BindingFlags.NonPublic;

возможность сериализации по умолчанию поддерживает все типы членов класса. Поэтому это решение вернет все типы частных членов, включая поля. Я заинтересован только в поддержке частных сеттеров.

Alt2: создать пользовательский ContractResolver:

поэтому это лучшие варианты, так как мы просто проверяем свойства.

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;
    }
}

для получения дополнительной информации, прочитайте мой пост:http://danielwertheim.se/json-net-private-setters/

@Daniel's answer (Alt2) находится на месте, но мне нужно было это работать как для частных сеттеров, так и для геттеров (я работаю с API, который на самом деле имеет несколько вещей только для записи, например user.password.) Вот что у меня получилось:

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;
    }
}

зарегистрирован таким образом:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
    ContractResolver = new NonPublicPropertiesResolver()
};