У меня есть класс и структура, показанные ниже. Если я сериализую класс как использует xmlserializer, я получаю:
<Тест>
<TestNumber1> 5 </ TestNumber1>
<InnerTest />
</ Тест>
каков самый простой способ правильно сериализовать InnerTest (желательно с использованием xmlserializer) без указания свойству Number a сеттер?
Спасибо, Ник
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; }}
}





Сам я никогда этого не делал, но подозреваю, что вам просто нужно реализовать интерфейс IXmlSerializable.
Насколько я могу судить, это означает, что вы имеют, чтобы сделать свою структуру изменяемой, что является проблемой. В идеале XmlSerializer должен распознавать, есть ли у вашего типа конструктор с определенной сигнатурой, но, поскольку это не вариант (насколько я понимаю), стоило бы реализовать интерфейс с использованием явной реализации интерфейса, чтобы хотя бы препятствовать пользователи не могут использовать его напрямую.
Интересно, как управляются другие структуры (например, DateTime) ... возможно, они имеют явную поддержку в XmlSerializer.
Класс XmlSerializer сериализует типы на основе System.TypeCode, возвращаемого методом Type.GetTypeCode (). Для DateTimes используется метод Convert.ToDateTime (String). К сожалению, все определяемые пользователем структуры обрабатываются как TypeCode.Object с целью сериализации с помощью XmlSerializer.
Как совершенно правильно говорит Джон Скит, вам нужно будет использовать IXmlSerializable с XmlSerializer, если вы не хотите иметь общедоступное получение / установку свойств, потому что оно предназначено для работы в среде с частичным доверием, поэтому не будет доступа ни к одному из них. данные, к которым вы все равно не могли получить доступ (чтобы ответить на его последнюю часть - да, некоторые структуры, такие как DateTime, действительно имеют явную поддержку в этом сериализаторе).
В зависимости от того, чего вы пытаетесь достичь и какую версию .NET вы используете, вы можете рассмотреть возможность использования DataContractSerializer, который не требует, чтобы что-то было общедоступным (например, вы можете поместить DataMemberAttribute в частное поле или свойство с публичным геттером и частным сеттером). Этот сериализатор дает вам меньше контроля над форматом XML (на самом деле он очень ограничен - например, он даже не поддерживает атрибуты!), Но несколько быстрее, чем окупаемость.
(Я давно мечтал о чем-то, что представляет собой комбинацию этих двух, то есть гибкости XmlSerializer с возможностью сериализации частных членов, таких как DataContractSerializer, но, к сожалению, на данный момент их нет.)
Если возможно в этом сценарии, я бы использовал 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)], но это не идеально).
Конечно, если у вас есть несколько значений в структуре ... сложнее. Конечно, у вас может быть несколько свойств прокладки, но это немного неаккуратно. По сути, [де] сериализация и неизменяемые объекты (как и должны быть структуры) не очень хорошо сочетаются.
Другой вариант - поддерживать отдельную версию POCO, которая использует изменяемые классы повсюду, и переводить между ними; опять же, не очень привлекательный вариант для моделей больших объектов.
Вы определенно можете использовать 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] и многие другие, которые можно настроить по мере необходимости.
Наслаждаться!
Привет, Джон, к сведению, у меня была такая же проблема (на самом деле у меня было довольно много), поэтому я просмотрел справочный источник XmlSerializer, и на самом деле объект DateTime обрабатывается особым образом.