Eu sei que há um atributo para lidar com setters privados, mas eu meio que quero esse comportamento como padrão. Existe uma maneira de fazer isso? Exceto ajustar a fonte. Seria ótimo se houvesse uma configuração para isso.
Eu sei que há um atributo para lidar com setters privados, mas eu meio que quero esse comportamento como padrão. Existe uma maneira de fazer isso? Exceto ajustar a fonte. Seria ótimo se houvesse uma configuração para isso.
Respostas:
Vim aqui procurando o atributo real que faz o Json.NET preencher uma propriedade somente leitura ao desserializar, e isso é simplesmente [JsonProperty]
, por exemplo:
[JsonProperty]
public Guid? ClientId { get; private set; }
Basta fornecer um construtor que tenha um parâmetro que corresponda à sua propriedade:
public class Foo
{
public string Bar { get; }
public Foo(string bar)
{
Bar = bar;
}
}
Agora isso funciona:
string json = "{ \"bar\": \"Stack Overflow\" }";
var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow
Prefiro essa abordagem sempre que possível, pois:
{ get; private set; }
e justo { get; }
.{get;private set;}
, não com{get;}
{ get; }
se o tipo tiver um construtor com um parâmetro correspondente ao nome da propriedade.
Eu escrevi um NuGet de distribuição de origem para isso, que instala um único arquivo com dois resolvedores de contrato personalizados:
Instale o NuGet:
Install-Package JsonNet.PrivateSettersContractResolvers.Source
Em seguida, basta usar qualquer um dos resolvedores:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
Você pode ler sobre isso aqui: http://danielwertheim.se/json-net-private-setters-nuget/
Repo do GitHub: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers
Existem duas alternativas que podem resolver o problema.
Alt 1: nos desserializadores
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
A opção de serialização padrão oferece suporte a todos os tipos de membros da classe. Portanto, esta solução retornará todos os tipos de membros privados, incluindo campos. Só estou interessado em também oferecer suporte a setters privados.
Alt2: Crie um ContractResolver personalizado:
Portanto, esta é a melhor opção, já que apenas verificamos as propriedades.
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;
}
}
Para obter mais informações, leia minha postagem: http://danielwertheim.se/json-net-private-setters/
DefaultMembersSearchFlags
foi descontinuado .
{get; }
NÃO é equivalente a { get; private set; }
. Para o primeiro caminho property.GetSetMethod(true)
retorna null
e o último true
. Isso me surpreendeu. Você deve ter private set;
para que a desserialização funcione conforme o esperado.
A resposta de @Daniel (Alt2) está correta, mas eu precisava que isso funcionasse para setters e getters privados (estou trabalhando com uma API que, na verdade, tem algumas coisas somente para gravação, como user.password
.) Aqui está o que eu terminei:
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;
}
}
Registrado assim:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
ContractResolver = new NonPublicPropertiesResolver()
};