Почему XmlSerializer так сложно использовать?
Я предполагаю использовать сериализацию XML следующим образом:
class Foo {
public Foo (string name) {
Name1 = name;
Name2 = name;
}
[XmlInclude]
public string Name1 { get; private set; }
[XmlInclude]
private string Name2;
}
StreamWriter wr = new StreamWriter("path.xml");
new XmlSerializer<Foo>().Serialize (wr, new Foo ("me"));
Edit: Я знаю, что этот код неверен. Это было просто, чтобы показать, как я хотел бы использовать его.
но это не работает вообще:
- XmlSerializer не является универсальным. Я должен бросить из и возражать против (de)сериализации.
- каждое свойство должно быть полностью публичным. Почему мы просто не используем Reflection для доступа к частным сеттерам?
- частная поля нельзя сериализовать. Я хотел бы украсить частные поля атрибутом, чтобы XmlSerializer включал их.
Я что-то пропустил, и XmlSerializer действительно предлагает описанные возможности? Существуют ли альтернативные сериализаторы XML, которые обрабатывают эти случаи более изощренно?
Если нет: мы все-таки в 2010 году, и .NET существует уже много лет. Сериализация XML часто используется, полностью стандартная и должна быть очень простой в выполнении. Или мое понимание может быть неправильным, и сериализация XML не должна раскрывать описанные функции по уважительной причине?
Edit: Legacy не является хорошей причиной imo. List
был неуниверсальных сначала.
(Не стесняйтесь настраивать заголовок или теги. Если это должен быть CW, пожалуйста, просто напишите записку.)
5 ответов
сначала фиксированный код, затем ответы на ваши вопросы:
public class Foo {
public Foo() : this("") {}
public Foo (string name) {
Name1 = name;
Name2 = name;
}
// note only this will be serialized
public string Name1 { get; private set; }
// this won't
private string Name2;
}
или в 3.0:
[DataContract]
class Foo {
public Foo (string name) {
Name1 = name;
Name2 = name;
}
[DataMember]
public string Name1 { get; private set; }
[DataMember]
private string Name2;
}
(и использовать DataContractSerializer
вместо XmlSerializer
)
XmlSerializer не является универсальным. Я должен бросить из и возражать против (de)сериализации.
это распространено для сериализаторов. У меня есть свой сериализатор, и изначально я сделал сделать его полностью универсальным. И это оказалось большой ошибкой дизайна. Огромный. Нет, серьезно. Я в настоящее время в процессе переписывания строка кода для переключения.
просто; сериализаторы обычно включают некоторый уровень отражения (либо для кода-gen, либо для фактической работы, в зависимости от реализации). Отражение и дженерики не играют хорошо, особенно на некоторых фреймворках, таких как WCF. Когда ваш код делает окончательный бросок, это справедливый компромисс. У меня есть записей в блоге об этом, если вы действительно хотеть...
каждое свойство должно быть полностью публичным.
это действительно ограничение XmlSerializer
(хотя список/полуботинки без сеттер в порядке, это будет бросьте, если у вас есть публичный get и частный набор). Кроме того, тип должен быть общедоступным и иметь конструктор без параметров.
почему мы просто не используем отражение для доступа к частным сеттерам?
для исполнения, XmlSerializer
строит сборку на лету, чтобы делать то, что вы хотите. Он не имеет автоматического доступа к внутренней части кода. Для информации я делаю что-то подобное, но я предлагаю 2 уровня генерации; полностью статический (в развертываемую dll), который затем работает только с общедоступными членами или в памяти, которая can еще доступ к закрытым членам. Я думаю, они хотели остановиться только на 1 модели, что имеет смысл - и им нужен "sgen", который диктует первую модель.
частные поля не могут быть сериализованы. Я хотел бы украсить частные поля атрибутом, чтобы XmlSerializer включал их.
затем использовать DataContractSerializer
, который будет сериализовать любой член (включая частный), отмеченный [DataMember]
.
посмотреть класс XmlSerializer. Вы увидите, что используете его неправильно. XmlInclude
имеет совершенно другую цель.
вы правы. Сериализатор XML существует с .NET 1.0. Это до того, как у нас были дженерики, кстати, так что вряд ли их поддержат.
кроме того, с тех пор появились лучшие технологии:
- DataContractSerializer работает быстрее и поддерживает сериализацию в двоичном формате
- LINQ к XML можно использовать в много сценарии сериализации, причем гораздо более гибкие
сериализатор XML вряд ли будет улучшен в будущем. Я рекомендую вам изучить другие альтернативы.
1: наследие. XML-сериализатор предшествует генерикам. Это как в .NET 1.0.
2: решение дизайна. XML-сериализатора должен работать с очень limtiedбыл прав, по сравнению с другими решениями.
3: то же, что и 2.
вы можете использовать сериализатор WCF DataContract по частям.
ваше предположение "ограничено неправильно". XML-сериализация предположительно предназначена для передачи документов, которые - в моих проектах - всегда являются отдельными классами, ничего не делающими. Как таковой, я никаких проблем со всеми ограничениями.
вам не нужно [XmlInclude] Как будто она у тебя есть. Вы можете использовать [XmlElement] [Xmlattribute с] ... Чтобы описать способ сериализации класса.
выньте [XmlInclude] и посмотрите, работает ли это.
class Foo {
public Foo (string name) {
Name1 = name;
Name2 = name;
}
[XmlAttribute]
public string Name1 { get; set; }
[XmlAttribute]
public string Name2;
}
Foo myFoo = new Foo("FirstName", "LastName");
StreamWriter wr = new StreamWriter("path.xml");
XmlSerializer serializer = new XmlSerializer(typeof(Foo));
serializer.Serialize(wr, myFoo);
Обновлено, сериализованные свойства должны быть общедоступными.
кстати DataContract никогда не поддерживает двоичную сериализацию, он сериализуется в xml, но поддерживает двоичное кодирование.