почему JavaScriptSerializer не может сериализовать внутренние свойства?

Я сериализовал пользовательский тип, который имеет некоторые внутренние свойства, но при сериализации кажется, что использование метода System.Web.Script.Serialization.JavaScriptSerializer serialize не сериализует внутренние свойства (поскольку он пропускает внутреннее свойство в сериализованной строке). Это легко понять из следующего кода и вывода:

public class MyClass
{
    public string Property1 { get; set; }

    internal string Property2 { get; set; }

    public string Property3 { get; set; }
}

JavaScriptSerializer mySerializer = new JavaScriptSerializer();
string jsonString = mySerializer.Serialize(new MyClass()
{
            Property1 = "One",
            Property2 = "Twp",
            Property3 = "Three"
});

JsonString имеет следующее значение:

{"Property1":"One","Property3":"Three"}

На выходе вы можете видеть, что у сериализованной строки нет свойства Property2, которое является внутренним свойством. Есть ли какая-то логика в том, что не поддерживает внутреннее свойство при сериализации?

Каким будет обходной путь для сериализации внутреннего свойства (кроме изменения внутреннего модификатора на общедоступный)?


person Akash KC    schedule 14.04.2016    source источник
comment
Кажется нелогичным, чтобы часть данных, помеченная как недоступная вне сборки (internal), также включалась по умолчанию в процесс отправки данных полностью в другое место (сериализация).   -  person Will Ray    schedule 14.04.2016
comment
@Will: Довольно сложно понять, почему MS учла проблему перекрестной сборки при сериализации, поскольку легко видеть, что сериализация выполняется в одной и той же сборке довольно часто   -  person Akash KC    schedule 14.04.2016


Ответы (2)


Это просто не поддерживается в System.Web.Script.Serialization.JavaScriptSerializer.

Я рекомендую вам перейти на Json.NET. Все, что вам нужно сделать в этом случае, - это пометить внутреннее свойство с помощью атрибута свойства json, и оно будет подхвачено сериализатором Json.NET.

[Newtonsoft.Json.JsonProperty]
internal string Property2 { get; set; }

Стоит отметить, что Json.NET намного производительнее.

На 50% быстрее, чем DataContractJsonSerializer, и на 250% быстрее, чем JavaScriptSerializer.

и имеет гораздо больше параметров конфигурации и в настоящее время является выбором Microsoft для .NET по умолчанию.

Согласно вашему запросу в комментариях, это возможно сделать с помощью библиотеки .NET FCL, если вы используете DataContractJsonSerializer, хотя это представляет собой собственный набор проблем с точки зрения api и необходимости отмечать каждый отдельный класс и свойство с помощью [DataContract] и [DataMember] соответственно.

using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

var instance = new MyClass {
        Property1 = "One",
        Property2 = "Twp",
        Property3 = "Three"
};

var ser = new DataContractJsonSerializer(instance.GetType());

using (MemoryStream ms = new MemoryStream())
{
    ser.WriteObject(ms, instance);
    string jsonData = Encoding.Default.GetString(ms.ToArray());
}

[DataContract]
public class MyClass
{
    [DataMember]
    public string Property1 { get; set; }
    [DataMember]
    internal string Property2 { get; set; }
    [DataMember]
    public string Property3 { get; set; }
}

Это правильно выведет

{"Property1":"One","Property2":"Twp","Property3":"Three"}

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

person David L    schedule 14.04.2016
comment
Мне просто любопытно узнать, почему он не поддерживается в System.Web.Script.Serialization.JavaScriptSerializer. Есть ли причина не поддерживать его? Да, я могу сделать это с помощью Newtonsoft, как вы указали, но для простой сериализации / десериализации я подумал, что JavaScriptSerializer подойдет. - person Akash KC; 14.04.2016
comment
Потому что, когда Microsoft написала это, они не приняли это во внимание. Вы должны спросить того, кто написал класс сериализатора :). Тем не менее, больше нет причин использовать JavaScriptSerializer. Это устаревший, медленный, неэффективный и причудливый. Вам следует перейти на более современный сериализатор. - person David L; 14.04.2016
comment
Есть ли у самого .NET FCL какой-либо другой способ сериализации / десериализации внутренних свойств? - person Akash KC; 14.04.2016
comment
Действительно, разрабатываемое мной приложение меньше (с точки зрения размера, мое приложение: 10 КБ и Newtonsoft: 475 КБ), поэтому я не решаюсь использовать стороннюю библиотеку (Newtonsoft) для выполнения простой задачи сериализации. Вопрос только для моего любопытства, иначе ваш ответ действительно отличный. - person Akash KC; 14.04.2016
comment
Я бы порекомендовал в этом случае сериализатор меньшего размера, если это возможно. Что-то вроде github.com/kevin-montrose/Jil может сработать для вас, хотя это может все еще будет слишком большим. Похоже, ваши проблемы с производительностью связаны с общим размером библиотеки, а не со скоростью, что означает, что вы можете застрять с DataContractJsonSerializer. - person David L; 14.04.2016
comment
Спасибо за попытку. Обязательно загляну в библиотеку Jil, которую слышал впервые :( - person Akash KC; 15.04.2016

Документация для JavaScriptSerializer находится на редкой стороне, я не смог найти ничего о том, как этот тип работает с модификаторы доступа.

internal скрывает Property2 от типов за пределами вашей сборки, поэтому я предполагаю, что в JavaScriptSerializer есть код, который спрашивает: «Какие свойства я могу видеть в этом объекте?»

Как вы видели, это сложный вопрос, и более надежные системы сериализации задают лучше задокументированный вопрос: «Какие свойства этого объекта аннотируются подсказками сериализации?»

См. JSON.net (как рекомендовано в документации JavaScriptSerializer) и DataContractJsonSerializer

person Matt Stephenson    schedule 14.04.2016
comment
Есть ли у самого .NET FCL какой-либо другой способ сериализации / десериализации внутренних свойств? - person Akash KC; 14.04.2016
comment
DataContractJsonSerializer должен уважать все свойства, помеченные DataMember, независимо от их модификатора доступа, IIRC. - person Matt Stephenson; 15.04.2016
comment
Кроме того, @LolCoder 아카 쉬 У меня появляется желание придерживаться вещей в базовых классах. Я работал в ситуациях, когда усилия по установке библиотек в продакшн быстро становились больше, чем попытки заново изобрести колеса из базовых классов. - person Matt Stephenson; 15.04.2016