Serializacja listy obiektów różnych typów (2)

0

Wątek jest w pewnym sensie kontynuacją tego:
http://4programmers.net/Forum/C_i_.NET/130379-dlugie_lista_obiektow_roznych_typow_-_zapisodczyt_do_pliku

W międzyczasie projekt zdążyłem porzucić i zacząć od nowa :), ale nie w tym rzecz. Co do jednego jestem przekonany - na pewno jest pieruńsko pouczający.

Tak, jak poprzednio - mam typ GameObject, z niego dziedziczy kilka innych typów (Creature:GameObject, Item:GameObject, Player:GameObject). Wszystkie mają kilka wspólnych metod (na przykład do wyświetlania na mapie). Wszystkie mają atrybut Serializable.

Oprócz tego, jest obiekt typu GameObjectList:List<GameObject> - do typowej listy dopisałem kilka metod - głównie służących do zapisu/odczytu z plików.

        public void save(string mapName)
        {
            StreamWriter sw;
            string dirPatch = "SaveGame\\" + mapName;
            
            for (int i=0; i<this.Count; i++)
            {
                sw = new StreamWriter(dirPatch + "\\obj" + i.ToString() + ".gmo");
                XmlSerializer ser = new XmlSerializer(typeof(GameObject), getAllObjectTypes() );//funkcja getAllObjectTypes zwraca tablicę wszystkich typów użytych w projekcie
                ser.Serialize(sw, this[i]);   //-----------------!!!!--------------------
                sw.Close();                
            }
        }
 
        public static MapObjectList load(string mapName)
        {
            StreamReader sr;
            string dirPatch = "SaveGame\\" + mapName;
            MapObjectList tempList = new MapObjectList();
            GameObject obj;
            XmlSerializer ser = new XmlSerializer(typeof(GameObject), getAllObjectTypes() ); //funkcja getAllObjectTypes zwraca tablicę wszystkich typów użytych w projekcie

            foreach (var fileName in Directory.GetFiles(dirPatch))
            {
                sr = new StreamReader(fileName);
                obj = (GameObject)ser.Deserialize(sr);
                tempList.Add(obj);
                sr.Close();
            }
            return tempList;           
        }        

Zaznaczam, że na tym etapie wszystko działa, i to bardzo fajnie.

Dopóki korzystam ze "standardowej" serializacji do XML.
Niestety, "standardowa" serializacja mi nie wystarcza, chciałbym ją sobie kontrolować. W tym celu dopisałem implementację interfejsu IXmlSerializable do klasy Player (tak na próbę):

 
    public class Player:Creature, IXmlSerializable
    {
//.........
        public string CharacterName;
        public int torchStrenght;

        public XmlSchema GetSchema()
        {
            return (null);
        }

        public void ReadXml(XmlReader reader)
        {
            CharacterName = reader.GetAttribute("CharacterName");
            torchStrenght = int.Parse(reader.GetAttribute("TorchStrenght"));
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("CharacterName", CharacterName);
            writer.WriteAttributeString("TorchStrenght", torchStrenght.ToString());
        }
    }

Dopisałem kawałek kodu, który z ręki generuje mi kilka obiektów, dodaje je do listy, i próbuje zserializować.
Niestety, w linijce oznaczonej wykrzyknikami, pojawia się wyjątek:
{"Wystąpił błąd podczas generowania dokumentu XML."}
Inner Exception:
{"Typ TestRougeGame2.Classes.Objects.Player nie może być używany w tym kontekście. Aby używać typu TestRougeGame2.Classes.Objects.Player jako parametru, typu zwracanego albo członka klasy lub struktury, parametr, typ zwracany lub członek musi zostać zadeklarowany jako typ TestRougeGame2.Classes.Objects.Player (nie może być obiektem). Obiekty typu TestRougeGame2.Classes.Objects.Player nie mogą być używane w kolekcjach nieokreślonego typu (np. ArrayLists)."}

Dalsze dochodzenie wykazało, że:
Poprawnie działa:

Player player = CreatePlayer();
XmlSerializer ser = new XmlSerializer(typeof(Player));
ser.Serialize(sw, player);
 

Natomiast wysypuje się (z wyjątkami identycznymi, jak poprzednio):

Player player = CreatePlayer();
GameObject obj = player;
XmlSerializer ser = new XmlSerializer(typeof(GameObject), Type[] {typeof(Player)});
ser.Serialize(sw, player);
 

Obydwa kawałki działają poprawnie, jeżeli klasa Player NIE implementuje interfejsu IXmlSerializable - ale wtedy tracę możliwość dokłądnej kontroli, co chcę serializować i jak.

Ktoś mi podpowie, jak to rozwiązać? (ewentualnie rzuci jakieś hasło do dalszego góglania)

0

Z tego co pamiętam, aby serializować i deserializować obiekty klas dziedziczących po klasie bazowej, trzeba dodać do klasy bazowej atrybut (tylko nie pamiętam jaki, tutaj poszukaj: http://msdn.microsoft.com/en-us/library/2baksw0z(v=vs.80).aspx )

1 użytkowników online, w tym zalogowanych: 0, gości: 1