2010-03-23 2 views
7

Я представляю себе, чтобы использовать XML-сериализации, как это:Почему XmlSerializer так трудно использовать?

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 не должна раскрывать описанные функции по уважительной причине?

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

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

+3

По той же причине, что рыть яму баскетболом так сложно. ;-) –

+3

Нельзя сказать, что «« Список »был сначала нерожденным». «List» был введен в 2.0 и тогда был общим классом. Более старый ненормальный 'ArrayList' является * другим * классом, который * все еще существует *. – AakashM

+0

Ooops. Ошибка с моей стороны. Я извиняюсь :) – mafu

ответ

10

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

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).

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

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

Каждого свойства должно быть полностью открытым.

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

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

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

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

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

+1

Ваш блог включен в мой список дел;) Хорошее объяснение! – mafu

7

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

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

3: так же, как 2.

Вы можете использовать WCF DataContract сериалайзер по частям.

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

11

См. XmlSerializer class. Вы увидите, что вы ошибаетесь. XmlInclude имеет совершенно другую цель.

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

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

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

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

+0

@Marc: 'DataContractSerializer' с' XmlDictionaryWriter.CreateBinaryWriter' не пишет двоичный файл? –

+0

достаточно справедливо; Я заберу это. –

1

[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

Если я не ошибаюсь, вы можете сериализовать публичные свойства. –

+0

Ну, это не работает, поскольку соответствующие сеттеры являются частными. - Редактировать: я медленный :) – mafu

+0

ваше право, я просто вырезал и вставлял то, что у него было, теперь оно обновлено. – galford13x

0

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

+0

@Kerem: DataContractSerializer с XmlDictionaryWriter.CreateBinaryWriter записывает двоичный файл. Что вы имеете в виду, когда говорите, что не поддерживает «двоичную сериализацию»? –

Смежные вопросы