2009-05-07 5 views
12

Мне нужно сохранить некоторые классы и структуры данных в файл. Мой первый рефлекс заключался в использовании XML или двоичной сериализации, но это превращается в кошмар. У меня есть набор классов, которые не предназначены для сериализации (частные сеттеры, без конструкторов без параметров, без атрибута сериализации, словарей и т. Д.). Учитывая, что я не могу изменить эти классы, что мне делать? Есть ли какое-либо обходное решение этого и по-прежнему использует сериализацию?Как сериализовать классы, не предназначенные для сериализации?

Должен ли я написать весь код для написания свойств, коллекций и т. Д.?

+0

Хороший вопрос, можете ли вы подробно рассмотреть требования к производительности и масштаб проблемы. –

+0

На данный момент у меня нет никаких требований. Я ищу наиболее элегантное решение. – Martin

+1

вы не можете разработать решение проблемы с нулевыми требованиями :) независимо от того, какое решение вы выбрали, скорее всего, это неправильное решение. На самом деле нет способа ответить на это, если нет требований ... –

ответ

9

Используйте JavaScriptSerializer. Он находится в пространстве имен System.Web.Script.Serialization и реализован в структуре 3.5 в сборке System.Web.Extensions.dll.

С помощью этого класса вы можете сериализовать любой POCO независимо от того, отмечен ли он как [Serializable] или нет. Ваша программа не обязательно должна быть веб-приложением для использования JSON-сериализации.Вот пример:

public class Unserializable 
{ 
    public int Age { get; set; } 
    public int ID { get; set; } 
    public string Name { get; set; } 
} 

public class Program 
{ 
    static void Main() 
    { 
    var u = new Unserializable 
      { 
       Age = 40, 
       ID = 2, 
       Name = "Betty" 
      }; 
    var jser = new JavaScriptSerializer(); 
    var jsonText = jser.Serialize(u); 
    // next line outputs {"Age":40,"ID":2,"Name":"Betty"} 
    Console.WriteLine(jsonText); 
    } 
} 
+0

+1, потому что я этого не знал. Также обрабатываются поля? –

+0

Да, он также обрабатывает поля. Попробуйте следующее: общественный класс Unserializable { общественный int Возраст; public int ID {get; задавать; } public string Имя {get; задавать; } public Unserializable (int age, int id, string name) { Возраст = возраст; ID = id; Name = name; } } var u = new Unserializable (40, 2, "Donna"); var jser = новый JavaScriptSerializer(); var jsonText = jser.Serialize (u); Console.WriteLine ("Сериализованный {0} с использованием" + "JavaScriptSerializer в {1}:", u.GetType(). Имя, jsonText); Это выводит текст JSON для объекта, содержащего общедоступное поле, как «{« Возраст »: 40,« ID »: 2,« Имя »:« Донна »} '. –

0

Я хотел бы использовать код поколения инструмент (mygeneration, T4, что угодно), чтобы генерировать DTOS сериализация ...

+0

Проблема с кодом, который делает ваш выход из этого, заключается в том, что если класс изменится, вам снова придется генерировать код. Это может быть или не быть проблемой. –

+0

Я не вижу причин для -1 этого ... –

0

Не простой обходной путь.

Возможно, вы хотите только сериализовать/десериализовать поля (частные и общедоступные) в классах и сделать это рекурсивно. Вам, вероятно, понадобится использовать рефлексию, чтобы добраться до них. Не деактивируйте/сериализуйте свойства, поскольку при установке значения свойства могут возникнуть побочные эффекты. Вам также придется рекурсивно де-сериализовать все поля, которые являются объектами. Задача состоит в том, чтобы знать, где остановиться.

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

Кроме того, вам придется называть параметризованные конструкторы и надеяться, что вы не наносите слишком большой урон при установке полей с отражением.

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

При этом код gen мог бы упростить задачу определения всех полей в классах.

0

Другой вариант - использовать шаблон адаптера.

Хорошей новостью является то, что вам не придется менять исходный класс. Плохая новость заключается в том, что вы, вероятно, закончите писать в два раза больше кода, чем в первом «неизменяемом» классе.

В результате вы получите 2 новых класса: адаптер и новый класс serializble.

Идея заключается в том, что адаптер знает, как создать серизуемый класс, изучив неэриализуемый класс. Чтобы пойти другим путем (сериализуемым к unserializable), вы можете снова использовать адаптер (конечно, здесь я предполагаю, что ваши частные сеттеры фактически установлены через параметризованный конструктор).

Here's the pattern in detail.

0

Есть две отдельные части к этому:

  1. извлечения/установки данных
  2. хранение/чтение его из файла (или в другом месте)

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

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

Использование среды, в которой вы хотите сохранить ее, например XML, и записать эти значения на диск.

Для десериализации прочитайте в значениях из файла, создайте новый экземпляр объекта и используйте отражение, чтобы установить все значения.

Если вы получаете/задаете все члены, у вас будет объект, который находится в идентичном состоянии. (Возможно, вам придется рекурсивно проходить все ваши объекты, если у вас есть сложные члены.)

Что касается того, как вы храните данные на диске, xml или двоичные файлы работают. Если вы хотите увидеть его и иметь его доступным для чтения, перейдите к XML. (Я бы рекомендовал это для вашего первоначального удара, так как это облегчит отладку.)

7

Звучит как работа для ... суррогатов сериализации!

Перейти к http://msdn.microsoft.com/en-us/magazine/cc188950.aspx

для обзора.

+0

+1: Суррогаты будут хорошо играть с BinaryFormatter. –

+0

Ссылка мертва, архив здесь: https://web.archive.org/web/20141231105711/http://msdn.microsoft.com/en-us/magazine/cc188950.aspx или MSDN: https: // msdn. microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=vs.110).aspx –

0

Это действительно зависит от масштаба вашей проблемы и производительности, в которой вы нуждаетесь.

Если у вас 1 класс проблем, я бы просто написал суррогатный класс, который может сериализовать/десериализовать этот класс. Если вы говорите о 100 классах, вам, вероятно, необходимо использовать структуру сериализации, которая поддерживает все тонкости. Никакая беззаботная конструкция не является кошмаром, независимо от того, какую структуру создания сериализации вы пишете или используете, вам нужно будет знать параметры, которые передают конструктору. Частные сеттеры/словари/списки и т. Д. Не слишком сложны.

Я написал фреймворк mini-serialization для медиа-браузера, который является BSD. Я сосредоточился на производительности, но методы, которые я использую, могут быть адаптированы к вашей проблеме. Аналогичным образом могут использоваться методы, используемые в Marc's protocol buffers.

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