NullReferenceException при десериализации массива структур

Рейтинг: 0Ответов: 1Опубликовано: 15.08.2023

у меня есть структура массивами обьектов, в одном файле должно храниться 1000 таких структур по 25 енамов и интов, я ее сохраняю,если нужно файл создается, но при попытке получить значение выдает ошибку, хотя по логике там должен быть просто 0

[System.Serializable]
public struct LvlData
{
    public BlockType[] blockTypes;
    public int[] blockPosX;
    public int[] blockPosY;
    public int[] blockPosZ;
}
public static LvlData GetData(string filepath, int arrayIndex)
{
    LvlData lvldata = new LvlData();

    if (File.Exists(filepath))
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(filepath, FileMode.Open);
        LvlData[] lvldataarray = (LvlData[])bf.Deserialize(file);
        file.Close();         
    }
    else Debug.LogError("cant find " + "file " + filepath);

    return lvldata;
}

public static void SetData(string filepath, int arrayIndex, LvlData lvldata)
{
    LvlData lvldataarray = new LvlData[1000];

    if (File.Exists(filepath))
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(filepath, FileMode.Open);
        lvldataarray = (LvlData[])bf.Deserialize(file);
        lvldataarray[arrayIndex] = lvldata;
        bf.Serialize(file, lvldataarray);
        file.Close();
    }
    else
    {
        Debug.Log("creating new file " + filepath);
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(filepath, FileMode.Create);
        bf.Serialize(file, lvldataarray);
        file.Close();
    }
}

 DataSaver.LvlData lvldata = new DataSaver.LvlData();
 string filepath = DataSaver.GetPath(lvlpos);//путь
 int index = DataSaver.GetIndex(lvlpos);//идекс
 lvldata = DataSaver.GetData(filepath, index);//получаем данные
 if (File.Exists(filepath))
 {
    Debug.Log(lvldata.blockTypes[11]); //тут возникает ошибка
 }

Ответы

▲ 0Принят

Вопрос решается стабилизацией кода. Для начала надо научиться нормально сохранять.

Метод не должен делать много дел одновременно, метод должен делать что-то одно.

public static void SaveData(string path, LvlData[] data)
{
    try
    {
        // перезапишет файл заново, если есть. создаст новый, если нет
        using (FileStream fs = File.Create(path))
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, data);
        }
    }
    catch (Exception ex)
    {
        Debug.LogError($"[SaveData] {ex.GetType().Name}: {ex.Message}");
    }
}

А десериализация будет выглядеть так

public static LvlData[] LoadData(string path)
{
    try
    {
        using (FileStream fs = File.OpenRead(path))
        {
            BinaryFormatter bf = new BinaryFormatter();
            return (LvlData[])bf.Deserialize(fs);
        }
    }
    catch (Exception ex)
    {
        Debug.LogError($"[LoadData] {ex.GetType().Name}: {ex.Message}");
    }
    return Array.Empty<LvlData>(); // пустой массив из 0 элементов
}

Всё стало очень просто, массив записали, массив прочитали. А уже за пределами этих методов если хотите, пересоздавайте массив, меняйте ему данные по индексам, что угодно. Главное, что теперь за сохранение и загрузку данных отвечает отдельно взятый код.


Я бы предложил отказаться от BinaryFormatter, он давно устарел, признан небезопасным и уже удален из современной версии .NET. Обычно разработчики используют JSON в наше время. Кстати, если LvlData содержит большой объем данных, я рекомендую использовать класс а не структуру.