Глубокая XML сериализация структуры Параметры - PullRequest
5 голосов
/ 15 января 2009

У меня есть класс и структура, показанные ниже. Если я сериализую класс как использует xmlserializer я получаю:

<Тест>
5 </ TestNumber1>

как проще всего правильно настроить сериализацию InnerTest (желательно с использованием xmlserializer) без присваивания свойству Number сеттер?

Спасибо, Ник

public class Test 
{ 
    private InnerTest innerTest; 
    private int testNumber; 


    public Test() 
    { 
        this.innerTest = new InnerTest(); 
        this.testNumber = 5; 
    } 


    public int TestNumber1 
    { 
        get { return this.testNumber; } 
        set { this.testNumber = value;} 
    } 


    public InnerTest InnerTest 
    { 
        get { return this.innerTest; } 
        set { this.innerTest = value;} 
    } 


} 


public struct InnerTest 
{ 
    private int number; 


    public InnerTest(int number) 
    { 
        this.number = number; 
    } 
    public int Number{get { return number; }} 
} 

Ответы [ 4 ]

2 голосов
/ 15 января 2009

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

В зависимости от того, что вы пытаетесь достичь, и какой версии .NET вы используете, вы можете рассмотреть возможность использования DataContractSerializer, который не требует, чтобы все было публично (например, вы могли бы поставить DataMemberAttribute в частном поле или в собственности с публичным геттером и приватным сеттером). Этот сериализатор дает вам меньше контроля над форматом XML (на самом деле он очень ограничительный - например, он даже не поддерживает атрибуты!), Но несколько быстрее в качестве окупаемости.

(Я долго занимался чем-то, что является комбинацией двух, то есть гибкостью XmlSerializer с возможностью сериализации частных членов, таких как DataContractSerializer, но, к сожалению, в настоящее время их нет.)

2 голосов
/ 15 января 2009

Если возможно в этом сценарии, я бы использовал DataContractSerializer (.NET 3.0), и я бы использовал что-то вроде:

[DataMember]
public int TestNumber1 
{ 
    get { return this.testNumber; } 
    set { this.testNumber = value;} 
} 

// note **not** a data-member
public InnerTest InnerTest 
{ 
    get { return this.innerTest; } 
    set { this.innerTest = value;} 
} 

[DataMember]
private int InnerTestValue
{
    get {return innerTest.Number;}
    set {innerTest = new InnerTest(value);}
}

таким образом обойдя проблему. Вы можете сделать то же самое с XmlSerializer, но вам нужно будет сделать InnerTestValue публичным (хотя вы можете украсить его с помощью [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] - но это не идеально).

Конечно, если у вас есть несколько значений в структуре ... хитрее. Конечно, у вас может быть несколько свойств прокладок, но это немного неаккуратно. По сути, [de] сериализация и неизменяемые объекты (как и должно быть в структурах) не очень хорошо сочетаются.

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

1 голос
/ 15 января 2009

Вы определенно можете использовать XmlSerializer на вашем объекте и получить ожидаемый результат:

Test test = new Test { TestNumber1 = 5 };

XmlSerializer xmlSer = new XmlSerializer(typeof(Test));
MemoryStream memStm = new MemoryStream();

xmlSer.Serialize(memStm, test);

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

StreamReader stmR = new StreamReader(memStm);
memStm.Position = 0;
string output = stmR.ReadToEnd();

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

Существует множество атрибутов, таких как [XmlIgnore] и многие другие, которые можно настроить по мере необходимости.

Наслаждайтесь!

1 голос
/ 15 января 2009

Я никогда не делал это сам, но я подозреваю, что вам просто нужно реализовать интерфейс IXmlSerializable .

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

Интересно, как справляются другие структуры (например, DateTime) ... возможно, они имеют явную поддержку в XmlSerializer.

...