Сериализация XML списка становится слишком большой - PullRequest
2 голосов
/ 13 ноября 2010

У меня есть приложение C # для форм Windows, которое запускает игру Trivia на IRC-канале и сохраняет задаваемые вопросы, а также таблицу лидеров (оценки) в классах, которые я сериализирую в XML для сохранения между сессиями. Проблема, с которой я столкнулся, лучше всего описана в потоке, так что вот она:

Пользователь X Получает запись в классе таблицы лидеров со счетом 1. Класс сохраняется в XML, XML содержит одну запись для пользователя X.

Пользователь Y получает запись в классе Leaderboard со счетом 1. Класс сохраняется в XML, XML содержит повторяющиеся записи для пользователя X и одну запись для пользователя Y.

После запуска в течение недели с менее чем 20 пользователями, я надеялся, что смогу написать веб-бэкэнд на PHP, чтобы помочь мне использовать результаты. Размер файла XML составляет 2 мегабайта.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;

namespace IRCTriviaBot
{
    [Serializable()]    
    public class LeaderBoard 
    {
        [Serializable()]
        public class Pair
        {
            public string user;
            public int score;
            public Pair(string usr, int scr)
            {
                user = usr;
                score = scr;
            }
            public Pair() { }
        }
        private static List<Pair> pairs = null;
        public List<Pair> Pairs
        {
            get
            {
                if (pairs==null)
                {
                    pairs = new List<Pair>();

                }
                return pairs;
            }
        }
        public LeaderBoard()
        {

        }
        public void newScore(string usr)
        {
            bool found = false;
            for (int i = 0; i < Pairs.Count && !found; ++i)
            {
                if (Pairs[i].user==usr)
                {
                    found = true; 
                    Pairs[i].score++;
                }
            }
            if (!found)
            {
                Pairs.Add(new Pair(usr, 1));
            }
        }

        public int getScore(string usr)
        {
            bool found = false;
            for (int i = 0; i < Pairs.Count && !found; ++i)
            {
                if (Pairs[i].user == usr)
                {
                    return Pairs[i].score;
                }
            }
            if (!found)
            {
                return 0;
            }
            return 0;
        }
    }
}

Здесь происходит сериализация и десериализация.

       void parseMessage(string message, string user = "")
    {
        if (message == "-startgame-")
        {
            if (!gameStarted)
            {
                gameStarted = true;
                openScores();
                startGame();
            }
        }
        else if (message == "-hint-")
        {
            if (!hintGiven && gameStarted)
            {
                sendMessage("Here's a better hint: " + Form2.qa.Answers[curQ].Trim());
                hintGiven = true;
            }

        }
        else if (message == "-myscore-")
        {
            sendMessage(user + ", your score is: " + leaderB.getScore(user));
        }

        else if (message.ToLower() == Form2.qa.Answers[curQ].ToLower())
        {
            if (gameStarted)
            {
                sendMessage(user + " got it right! Virtual pat on the back!");
                leaderB.newScore(user);
                saveScores();
                System.Threading.Thread.Sleep(2000);
                startGame();
            }
        }
        else if (message == "-quit-")
        {
            if (gameStarted)
            {
                sendMessage("Sorry to see you go! Have fun without me :'(");
                gameStarted = false;
            }
            else
            {
                sendMessage("A game is not running.");
            }
        }
        else
        {
            if (gameStarted)
            {
                //sendMessage("Wrong.");
            }
        }
    }

    void saveScores()
    {
        //Opens a file and serializes the object into it in binary format.
        Stream stream = System.IO.File.Open("scores.xml", FileMode.Open);
        XmlSerializer xmlserializer = new XmlSerializer(typeof(LeaderBoard));

        //BinaryFormatter formatter = new BinaryFormatter();

        xmlserializer.Serialize(stream, leaderB);
        stream.Close();
    }

    void openScores()
    {
        Stream stream = System.IO.File.OpenRead("scores.xml");
        XmlSerializer xmlserializer = new XmlSerializer(typeof(LeaderBoard));

        //BinaryFormatter formatter = new BinaryFormatter();

        leaderB = (LeaderBoard)xmlserializer.Deserialize(stream);
        stream.Close();
    }

1 Ответ

1 голос
/ 13 ноября 2010

Я думаю, что это связано с pairs, помеченным static. Я не верю, что XmlSerializer очистит список перед добавлением в него элементов, поэтому каждый раз, когда вы вызываете openScores(), вы будете создавать повторяющиеся записи, а не перезаписывать существующие.

В общем, я заметил, что сериализация и глобальные переменные плохо сочетаются друг с другом. Для этой цели «глобальные переменные» включают частные статические элементы, синглтоны, классы monostate , подобные этому, и локальные переменные потока.

Похоже, что между использованием XML и двоичной сериализацией существует некоторая проблема. Это совершенно разные звери. XML-сериализация смотрит только на общие свойства класса, в то время как двоичная сериализация смотрит только на поля экземпляра класса. Кроме того, сериализация XML игнорирует атрибут Serializable.

...