Я создаю игру XNA и пытаюсь полностью сохранить состояние игры / карты и т. Д., А затем могу загрузить и возобновить работу из точно такого же состояния.
Моя игровая логика состоит из довольно сложных элементов (для сериализации), таких как ссылки, делегаты и т. Д. Я провел часы исследований и решил, что лучше всего использовать DataContractSerializer
, который сохраняет ссылки на объекты. (Я также обошел делегатов, но это уже другая тема) У меня нет проблем с сериализацией и десериализацией состояния, воссозданием объектов, полей, списков и даже ссылок на объекты правильно и полностью. Но у меня проблема с циклическими ссылками. Рассмотрим этот сценарий:
class X{
public X another;
}
//from code:
X first = new X();
X second = new X();
first.another = second;
second.another = first;
Попытка сериализации X приведет к исключению с жалобами на циклические ссылки. Если я закомментирую последнюю строку, она работает нормально. Ну, я могу представить, ПОЧЕМУ это происходит, но я понятия не имею, КАК это решить. Я где-то читал, что я могу использовать атрибут DataContract
с IsReference
, установленным в true, но это ничего не изменило для меня - все равно получена ошибка. (В любом случае, я хочу избежать этого, поскольку код, над которым я работаю, является переносимым кодом и может когда-нибудь работать и на Xbox, а переносимая библиотека для Xbox не поддерживает сборку, в которой находится DataContract
.)
Вот код для сериализации:
class DataContractContentWriterBase<T> where T : GameObject
{
internal void Write(Stream output, T objectToWrite, Type[] extraTypes = null)
{
if (extraTypes == null) { extraTypes = new Type[0]; }
DataContractSerializer serializer = new DataContractSerializer(typeof(T), extraTypes, int.MaxValue, false, true, null);
serializer.WriteObject(output, objectToWrite);
}
}
и я вызываю этот код из этого класса:
[ContentTypeWriter]
public class PlatformObjectTemplateWriter : ContentTypeWriter<TWrite>
(... lots of code ...)
DataContractContentWriterBase<TWrite> writer = new DataContractContentWriterBase<TWrite>();
protected override void Write(ContentWriter output, TWrite value)
{
writer.Write(output.BaseStream, value, GetExtraTypes());
}
и для десериализации:
class DataContractContentReaderBase<T> where T: GameObject
{
internal T Read(Stream input, Type[] extraTypes = null)
{
if (extraTypes == null) { extraTypes = new Type[0]; }
DataContractSerializer serializer = new DataContractSerializer(typeof(T), extraTypes, int.MaxValue, false, true, null);
T obj = serializer.ReadObject(input) as T;
//return obj.Clone() as T; //clone falan.. bi bak iste.
return obj;
}
}
и он вызывается:
public class PlatformObjectTemplateReader : ContentTypeReader<TRead>
(lots of code...)
DataContractContentReaderBase<TRead> reader = new DataContractContentReaderBase<TRead>();
protected override TRead Read(ContentReader input, TRead existingInstance)
{
return reader.Read(input.BaseStream, GetExtraTypes());
}
где:
PlatformObjectTemplate
был мой тип, чтобы написать.
Есть предложения?
РЕШЕНИЕ : Всего несколько минут назад я понял, что не отмечал поля атрибутом DataMember
, и до того, как я добавил атрибут DataContract
, сериализатор XNA был каким-то образом действующий как сериализатор по умолчанию. Теперь я пометил все объекты, и теперь все работает отлично. Теперь у меня есть циклические ссылки без проблем в моей модели.