Я знаю, что есть атрибут для обработки частных установщиков, но я хочу, чтобы это поведение использовалось по умолчанию, есть ли способ сделать это? За исключением настройки источника. Было бы здорово, если бы для этого была настройка.
Ответы:
Я пришел сюда в поисках фактического атрибута, который заставляет 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; }.{get;private set;}{get;}
{ get; }если у типа есть конструктор с параметром, соответствующим имени свойства.
Я написал для этого исходный дистрибутив NuGet, который устанавливает один файл с двумя настраиваемыми преобразователями контрактов:
Установите 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: 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/
DefaultMembersSearchFlagsбыло устаревшим .
{get; }НЕ эквивалентен { get; private set; }. По первому способу property.GetSetMethod(true)возвращается nullи второй true. Это меня удивило. Вы должны иметь, private set;чтобы десериализация работала должным образом .
Ответ @ Daniel (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()
};