Почему 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, но поддерживает двоичное кодирование.