Почему XmlSerializer так сложно использовать? - PullRequest
7 голосов
/ 23 марта 2010

Я предполагаю использовать сериализацию 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"));

Редактировать: Я знаю, что этот код неверен. Это было просто, чтобы показать, как я хотел бы использовать его.

Но это совсем не работает:

  • XmlSerializer не является универсальным. Я должен привести от объекта к объекту (де) сериализации.
  • Каждая собственность должна быть полностью публичной. Почему мы не просто используем Reflection для доступа к частным сеттерам?
  • Частные поля не могут быть сериализованы. Я хотел бы украсить приватные поля атрибутом, чтобы XmlSerializer включал их.

Я что-то упустил, и XmlSerializer действительно предлагает описанные возможности? Существуют ли альтернативные сериализаторы XML, которые обрабатывают эти случаи более изощренно?

Если нет: мы находимся в 2010 году, и .NET существует уже много лет. Сериализация XML часто используется, полностью стандартна и должна быть действительно простой в исполнении. Или мое понимание, возможно, неверно, и сериализация XML не должна раскрывать описанные функции по уважительной причине?

Редактировать: Наследие не является хорошей причиной, имо. List поначалу тоже не было общим.

(Не стесняйтесь корректировать заголовок или теги. Если это должен быть CW, просто оставьте записку.)

Ответы [ 5 ]

11 голосов
/ 23 марта 2010

См. Класс XmlSerializer . Вы увидите, что вы используете это неправильно. XmlInclude имеет совершенно другое назначение.

Ты прав. Сериализатор XML существует с .NET 1.0. Это было до того, как у нас появились дженерики, поэтому вряд ли их поддержат.

Кроме того, с тех пор появились лучшие технологии:

  • DataContractSerializer работает быстрее и поддерживает сериализацию как двоичный файл
  • LINQ to XML может использоваться во многих сценариях сериализации и является гораздо более гибким

Сериализатор XML вряд ли будет улучшен в будущем. Я рекомендую вам изучить другие альтернативы.

10 голосов
/ 23 марта 2010

Сначала фиксированный код, затем ответы на ваши вопросы:

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 не является универсальным. Я должен привести от объекта к объекту (де) сериализации.

Это характерно для сериализаторов. У меня есть свой собственный сериализатор, и первоначально я сделал сделать его полностью универсальным. И это оказалось большой ошибкой дизайна. Огромный. Нет, серьезно. В настоящее время я переписываю каждую строку кода, чтобы отключить ее.

Просто; Сериализаторы обычно предполагают некоторый уровень отражения (для кода или для фактической работы, в зависимости от реализации). Отражение и дженерики не очень хорошо играют, особенно на некоторых платформах, таких как WCF. Выполнение финального приведения вашего кода - это честный компромисс. У меня есть число записей в блоге, если вы действительно хотите ...

Каждая собственность должна быть полностью публичной.

Это действительно ограничение XmlSerializer (хотя список / коллекция без с установщиком в порядке, он выбросит , если у вас есть общедоступный набор get и private). Кроме того, тип должен быть открытым и иметь конструктор без параметров.

Почему мы не просто используем Reflection для доступа к частным сеттерам?

Для производительности XmlSerializer строит сборку на лету, чтобы делать то, что вы хотите. Он не имеет автоматического доступа к внутренностям вашего кода. Для информации я делаю нечто подобное, но я предлагаю 2 уровня генерации; полностью статический (в развертываемой dll), который затем работает только с открытыми членами или в памяти, которая может по-прежнему обращаться к закрытым членам. Я думаю, что они хотели остановиться только на 1 модели, которая имеет смысл - и им нужен был «sgen», который диктует первую модель.

Закрытые поля нельзя сериализовать. Я хотел бы украсить приватные поля атрибутом, чтобы XmlSerializer включал их.

Затем используйте DataContractSerializer, который будет сериализовать любого участника (включая частного), помеченного [DataMember].

7 голосов
/ 23 марта 2010

1: наследие. Сериализатор XML предшествует дженерикам. Это как в .NET 1.0.

2: проектное решение. XML-сериализатор должен работать с очень ограниченными правами по сравнению с другими решениями.

3: то же, что и 2.

Сериализатор WCF DataContract можно использовать по частям.

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

1 голос
/ 23 марта 2010

Вам не нужно [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);

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

0 голосов
/ 25 марта 2010

Кстати, DataContract никогда не поддерживает двоичную сериализацию, он сериализуется в XML, но поддерживает двоичное кодирование.

...