Почему установщик моего свойства filename не выполняется, если он отсутствует в JSON?
Как я могу получить желаемый результат, если я не могу использовать сеттер?
См. упрощенный пример ниже:
using System;
using Newtonsoft.Json;
namespace JsonDeserializeNulls
{
class Program
{
static void Main(string[] args)
{
var json1 = "{\r\n\t\"encoding\": \"base64\"\r\n}";
var json2 = "{\r\n\t\"encoding\": \"base64\",\r\n\t\"filename\": null,\r\n}";
var document1 = JsonConvert.DeserializeObject<Document>(json1);
var document2 = JsonConvert.DeserializeObject<Document>(json2);
Console.WriteLine(document1.ToString());
Console.WriteLine(document2.ToString());
Console.ReadLine();
}
}
public class Document
{
public string Encoding { get; set; }
private string _filename;
public string Filename
{
get => _filename;
set => _filename = string.IsNullOrEmpty(value) ? "NoFilenameSupplied" : value;
}
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
}
Выход:
{"Encoding":"base64","Filename":null}
{"Encoding":"base64","Filename":"NoFilenameSupplied"}





JsonConvert не будет вызывать сеттер, он просто напрямую загружает данные в объект. Вам лучше написать так:
public class Document
{
public string Encoding { get; set; }
public string Filename { get; set; }
public string SafeFilename => string.IsNullOrEmpty(Filename) ? "NoFilenameSupplied" : Filename;
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
Теперь вы можете использовать SafeFilename в своем коде, чтобы всегда получать желаемое значение!
Он должен работать. Значение будет десериализовано в свойство Filename. Что заставляет вас верить, что это не сработает?
Это не сработает. Имя файла — это частное свойство, которое не будет устанавливаться десериализатором.
Есть несколько проблем с этим - Создает ненужное дополнительное свойство. Когда вы сериализуете этот объект, это свойство теперь будет существовать в файле json.
Думаю, в зависимости от варианта использования вы можете просто использовать аннотацию данных, чтобы убедиться, что они не сериализованы. Я согласен, однако, что в оптимальной архитектуре будет присутствовать разделение между Model и ViewModel, и ViewModel будет иметь эту функциональность.
Добавьте конструктор по умолчанию и инициализируйте _filename значением NoFilenameSupplied.
Редактировать:
Десериализатор сначала вызовет конструктор по умолчанию, установив для _filename значение NoFilenameSupplied. Даже если свойство FileName отсутствует в JSON, это гарантирует, что свойство задано надлежащим образом.
Если вам не нравится добавлять проверку в сеттер, вы также можете сделать это:
[DefaultValue("")]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore,DefaultValueHandling = DefaultValueHandling.Ignore)]
public string FileName { get; set; }
Это укажет десериализатору JSON.NET не устанавливать свойство, если значение в JSON равно null или значение по умолчанию типа (строка), которое снова равно null. Мы меняем это, используя атрибут DefaultValue, заставляющий десериализатор думать, что значение этого свойства по умолчанию — String.Empty, а не нуль, благодаря чему NullValueHandling и DefaultValueHandling работают должным образом.
Добавлено пояснение к ответу.
Благодарю. Раздражает, что мне приходится устанавливать «NoFilenameSupplied» в двух местах. Мне придется создать постоянный файл, на который оба указывают, я думаю!
@chris Я пересмотрел ответ, чтобы избежать этого.
Но это никогда не установит имя файла, если указано значение, например
{ "encoding": base64", "filename": "test" }?