Почему я не могу сериализовать свойство с приватным сеттером (C#, json)

Я использую dotnet core 2.1 и создал помощник для сериализации из и в JSON. Он основан на System.Runtime.Serialization.Json, который поставляется с ядром dotnet.

Я не хочу использовать JSON.NET lib по некоторым причинам (здесь это не имеет значения)

Я столкнулся с ошибкой, которую не понимаю. Вот класс Helper, который я сделал (я только что оставил метод ToJson, так как именно здесь возникает моя проблема)

public static class JsonUtils
{
    private static readonly DataContractJsonSerializerSettings _jsonSettings = new DataContractJsonSerializerSettings
    {
        UseSimpleDictionaryFormat = true,
        SerializeReadOnlyTypes = true,
        EmitTypeInformation = EmitTypeInformation.Never
    };

    public static string ToReadableJson<T>(T o)
    {
        string res = null;

        try
        {
            using (var ms = new MemoryStream())
            using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.UTF8, true, true, "  "))
            {
                var serializer = new DataContractJsonSerializer(typeof(T), _jsonSettings);
                serializer.WriteObject(writer, o);
                writer.Flush();

                ms.Position = 0;

                using (var sr = new StreamReader(ms))
                {
                    res = sr.ReadToEnd();
                }
            }
        }
        catch
        { }

        return res;
    }
}

Все работало нормально, пока я недавно не заметил, что некоторые объекты просто игнорируются, если их свойства имеют не общедоступный сеттер. Я не понимаю, почему сеттер должен быть общедоступным, он просто должен читать данные для сериализации, верно?

Вот небольшой код для тестирования:

public class TestSubObject
{
    public string Property { get; set; } = "Bar";
}

public class TestObject
{
    public TestSubObject Sub { get; set; }
    public string Property { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var o = new TestObject
        {
            Property = "Foo",
            Sub = new TestSubObject()
        };

        string json = JsonUtils.ToReadableJson<TestObject>(o);
        Console.WriteLine(json);

        Console.Read();
    }
}

В этом примере у меня есть только корневой объект (TestObject), который имеет другой сложный объект в качестве свойства (TestSubObject).

В этом случае работает:

ОК

Затем, если я изменю установщик TestSubObject.Property с общедоступного на частный, он больше не будет работать. (В моем реальном случае класс находится в другой сборке с «внутренним» набором)

НОТОК

Мое вспомогательное свойство исчезло.

Как видите, я проверил DataContractJsonSerializerSettings и уже установил для SerializeReadOnlyTypes значение true, но это ничего не меняет.

Да, я могу отредактировать свои классы, чтобы сделать их общедоступными, но я этого не понимаю, поэтому я публикую это здесь, если у кого-то есть идеи.

Спасибо


person kipy    schedule 18.05.2019    source источник
comment
Итак... вы хотите, чтобы сериализация добавляла данные, которые десериализация будет вынуждена игнорировать? - Приложение: или еще хуже, бросить, потому что он не может его установить. Возможно, сериализация должна сбросить, чтобы вы знали о проблеме раньше.   -  person Theraot    schedule 18.05.2019
comment
вы хотите, чтобы сериализация добавляла данные, которые десериализация будет вынуждена игнорировать -> это имеет смысл :) Но да, эти данные вычисляются, и их не нужно считывать из json. В обоих случаях исключений не возникает. Я просто удалил ненужные строки из исходного кода, чтобы упростить пример. Спасибо за ваш ответ   -  person kipy    schedule 18.05.2019


Ответы (1)


Когда вы используете System.Runtime.Serialization без каких-либо аннотаций, он будет игнорировать свойства, которые не могут быть установлены, и сериализовать все общедоступные члены данного типа, которые могут быть сериализованы и десериализованы.

Однако, если вы выберете явное объявление того, что он должен сериализовать, он будет работать:

[DataContract]
public class TestSubObject
{
    [DataMember]
    public string Property { get; private set; } = "Bar";
}

[DataContract]
public class TestObject
{
    [DataMember]
    public TestSubObject Sub { get; set; }
    [DataMember]
    public string Property { get; set; }
}

Выход:

{
  "Property": "Foo",
  "Sub": {
    "Property": "Bar"
  }
}
person mwilczynski    schedule 18.05.2019