【问题标题】:Load serialized data in multiple applications C#在多个应用程序 C# 中加载序列化数据
【发布时间】:2015-07-30 11:15:05
【问题描述】:

场景: 我有一个程序,它使用一个简单的类来生成游戏数据。使用上述程序,我使用序列化和 BinaryFormatter 将数据写入文件以供第二个程序使用。从这个初始程序中读取数据没有问题。

问题: 这可能是由于我对序列化文件的处理方式一无所知,但我无法将这些数据加载到第二个程序中,即实际游戏本身。

保存游戏代码(在程序 1 中):

static List<GameData> gameData;
static GameData currentData;

private void saveGame(Sudoku sdk) {
    BinaryFormatter bf = new BinaryFormatter();
    FileStream file = null;
    try {
        if(!File.Exists(gameDataFile[currentDifficulty])) {
            file = File.Open(gameDataFile[currentDifficulty], FileMode.CreateNew);
        } else {
            file = File.Open(gameDataFile[currentDifficulty], FileMode.Append);
        }
        currentData = setGameData(sdk);
        bf.Serialize(file, currentData);
        savePuzzleLog();
    } catch(Exception e) {
        Debug.LogException("saveGame", e);
    }
    if(file != null) {
        file.Close();
    }
}

loadGameData:(在程序 2 中)

public static List<GameData> gameData;

public bool loadGameData() {
    if(gameData == null) {
        gameData = new List<GameData>();
    } else {
        gameData.Clear();
    }
    bool loadData = true;
    bool OK = false;
    if(File.Exists(gameDataFile[currentDifficulty])) {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(gameDataFile[currentDifficulty], FileMode.Open);
        while(loadData) {
            try {
                GameData gd = new GameData();
                gd = (GameData)bf.Deserialize(file);
                gameData.Add(gd);
                OK = true;
                if(file.Position == file.Length) {
                    loadData = false;
                }
            } catch(Exception e) {
                Debug.LogException(e);
                loadData = false;
                OK = false;
            }
        }
        if(file != null) {
            file.Close();
        }
    } else {
        Debug.LogWarning(gameDataFile[currentDifficulty] + " does not exist!");
    }
    return OK;
}

GameData 类:(第一个程序)

[Serializable]
class GameData {
    private int gameID;
    private List<int> contentArray;
    private int difficultyValue;

    public GameData(List<int> data = null) {
        id = -1;
        difficulty = -1;
        if(content != null) {
            content.Clear();
        } else {
            content = new List<int>();
        }
        if(data != null) {
            foreach(int i in data) {
                content.Add(i);
            }
        }
    }

    public int id {
        get {
            return this.gameID;
        }
        set {
            this.gameID = value;
        }
    }

    public int difficulty {
        get {
            return this.difficultyValue;
        }
        set {
            this.difficultyValue = value;
        }
    }

    public List<int> content {
        get {
            return this.contentArray;
        }
        set {
            this.contentArray = value;
        }
    }
}

GameData 类:(第二个程序)唯一的区别是声明为公共

[Serializable]
public class GameData {
    private int gameID;
    private List<int> contentArray;
    private int difficultyValue;

    public GameData(List<int> data = null) {
        id = -1;
        difficulty = -1;
        if(content != null) {
            content.Clear();
        } else {
            content = new List<int>();
        }
        if(data != null) {
            foreach(int i in data) {
                content.Add(i);
            }
        }
    }

    public int id {
        get {
            return this.gameID;
        }
        set {
            this.gameID = value;
        }
    }

    public int difficulty {
        get {
            return this.difficultyValue;
        }
        set {
            this.difficultyValue = value;
        }
    }

    public List<int> content {
        get {
            return this.contentArray;
        }
        set {
            this.contentArray = value;
        }
    }
}

我的问题是,我如何将数据保存在一个程序中并能够使用不同的程序加载它而不会出现序列化错误,或者我是否需要使用备用保存/加载方法和/或类结构?

【问题讨论】:

  • 我确实试图回答你,但我不得不完全猜测你的问题是什么,一条错误消息(你所说的异常)会很有帮助
  • 如果您在同一个程序集中序列化/反序列化数据,使用BinaryFormatter。还有很多其他的序列化器,不清楚为什么一定要用这个序列化器。
  • 在游戏中,我赌的是反作弊 :),基于文本的序列化程序会生成一个太容易修改的文件
  • 也许我应该解释一下,辅助应用程序是用 Unity 编写的,我收到的错误是:FileNotFoundException:无法加载文件或程序集'Sudoku Manager,Version=1.0.0.0,Culture=neutral, PublicKeyToken=null' 或其依赖项之一。该系统找不到指定的文件。 ...其中“Seduko Manager”是生成数据文件的程序 1 的名称。 @Sidewinder94 你是绝对正确的,正如你所说,这是为了反作弊,使用基于文本的文件很容易找到解决方案。

标签: c# serialization binaryfiles binary-data


【解决方案1】:

当我不得不这样做时,我是这样做的:

一个独立的 dll(程序集),包含保存数据的类(为您提供 GameData 类),以及从文件中保存/加载的实用方法。

您的另外两个项目必须引用此 dll(程序集),并且您应该能够正确(反)序列化。

我认为您的问题在于 BinaryFormatter 不仅将数据保存在文件中,而且还保存了序列化对象的完整类型。

当你尝试在另一个类似的对象中反序列化时,即使结构相同,类的全名也不是(因为程序集名不是)。

【讨论】:

  • 有没有办法添加哈希码或程序必须知道的任何内容才能读取数据,而不是程序集名称/版本。正如我所解释的,这可能是我对序列化如何工作的误解导致了这个问题。我知道我可以轻松切换到结构并解决它,但从我所读到的内容来看,结构已成为过去,应该改用类,还是我也误解了?
  • 不,没有办法使用哈希,这是二进制序列化在 .NET 中的工作方式。正如我所说,您必须创建一个包含 GameData 类的第三个项目(一个 dll 项目)。然后,您必须在两个项目(管理器和游戏)中引用此 dll 才能正确(反)序列化
【解决方案2】:

好的,我已经按照给出的建议对其进行了排序。我没有使用 BinaryFormatter,而是使用了 BinaryWriter 和 BinaryReader,如下所示...

在程序 1(创建者)中:

    private byte[] setByteData(Sudoku sdk) {
        List<int> clues = sdk.puzzleListData();
        byte[] bd = new byte[puzzleSize];
        SudokuSolver solver = new SudokuSolver();
        List<int> solution = solver.Solve(sdk.Copy(), false, currentDifficulty).puzzleListData();
        for(int i = 0; i < puzzleSize; i++) {
            bd[i] = Convert.ToByte(solution[i] + (clues[i] == 0 ? 0xF0 : 0));
        }
        return bd;
    }

    private GameData setGameData(Sudoku sdk) {
        List<int> clues = sdk.puzzleListData();
        GameData gd = new GameData();
        gd.id = puzzleList.Items.Count;
        gd.difficulty = currentDifficulty;
        SudokuSolver solver = new SudokuSolver();
        List<int> solution = solver.Solve(sdk.Copy(), false, currentDifficulty).puzzleListData();
        for(int i = 0; i < puzzleSize; i++) {
            gd.content.Add(solution[i] + (clues[i] == 0 ? 0xF0 : 0));
        }
        return gd;
    }

    private List<int> getByteData(byte[] data) {
        List<int> retVal = new List<int>();
        foreach(byte i in data) {
            if(i > 9) {
                retVal.Add(i - 0xF0);
            } else {
                retVal.Add(0);
            }
        }
        return retVal;
    }

    private string getGameData(List<int> data) {
        string retVal = "";
        foreach(int i in data) {
            if(i > 9) {
                retVal += (i - 0xF0).ToString();
            } else {
                retVal += i.ToString();
            }
        }
        return retVal;
    }

    private void saveGame(Sudoku sdk) {
        FileStream file = null;
        BinaryWriter bw = null;
        try {
            if(!File.Exists(gameDataFile[currentDifficulty])) {
                file = File.Open(gameDataFile[currentDifficulty], FileMode.CreateNew);
            } else {
                file = File.Open(gameDataFile[currentDifficulty], FileMode.Append);
            }
            bw = new BinaryWriter(file);
            currentData = setGameData(sdk);
            byte[] bd = setByteData(sdk);
            bw.Write(currentData.id);
            bw.Write(currentData.difficulty);
            bw.Write(bd);
            savePuzzleLog();
        } catch(Exception e) {
            Debug.LogException("saveGame", e);
        }
        if(file != null) {
            if(bw != null) {
                bw.Flush();
                bw.Close();
            }
            file.Close();
        }
    }

在程序2中:(实际游戏)

    public bool loadGameData() {
        if(gameData == null) {
            gameData = new List<GameData>();
        } else {
            gameData.Clear();
        }
        bool loadData = true;
        bool OK = false;
        if(File.Exists(gameDataFile[currentDifficulty])) {
            FileStream file = File.Open(gameDataFile[currentDifficulty], FileMode.Open);
            BinaryReader br = new BinaryReader(file);
            while(loadData) {
                try {
                    GameData gd = new GameData();
                    gd.id = br.ReadInt32();
                    gd.difficulty = br.ReadInt32();
                    gd.content = getByteData(br.ReadBytes(puzzleSize));
                    gameData.Add(gd);
                    OK = true;
                    if(file.Position == file.Length) {
                        loadData = false;
                    }
                } catch(Exception e) {
                    Debug.LogException(e);
                    loadData = false;
                    OK = false;
                }
            }
            if(file != null) {
                file.Close();
            }
        } else {
            Debug.LogWarning(gameDataFile[currentDifficulty] + " does not exist!");
        }
        return OK;
    }

类结构与以前相同,但使用此方法解决了我的问题,我现在可以使用我的创建器创建数据文件并使用实际游戏轻松加载数据。

感谢大家的帮助和建议,帮助我解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多