I have a file editor. It reads from a file, creates an object with the read data and can then write that data into a same (or another) file.Every time user opens a file a new tab is created and a private instance of the object is assigned to it, containing it in the tab. The object itself is complex and is composited of other objects. Each custom type has a Write() and Read() methods that extract and save data from and into the file. Something like this:TopObject a0    int a    int b    string c    CustomObjectMid d        int e        bool f    List<CustomObjectMid2> g    CustomObjectMid3 h        CustomObjectBottom i            long j            ulong k        Dictionary<string, int> l    byte mThe real object is much bigger and has more depth (levels) to it.TopObject, CustomObjectMid, CustomObjectMid2, CustomObjectMid3 and CustomObjectBottom all have a Write() and Read() methods that populate all standard types with data from file. They don't contain any other methods. They don't even have constructors (other than the default).The sole purpose of this object is to hold information. It's essentially a structure. This is actually written as a DLL which purpose it to enable users to make sense of that particular file format (read from it and write to it). So the actual code is not in my program, but is a part of a library. As such, I'd like to keep the library relatively neutral - I don't want to implement code that is specific to the editor into the library.The way this object is implemented is that everything is public and I can access anything in a0.h.i.j manner. I tend to pass relevant parts of the objects to pieces of program that use it, so I don't have to reference to everything from the top (a0).Other parts of the program display the data to the user and translate the changes user makes into the object. They also perform the necessary checks to keep the integrity of data (prevent passing of chars for ints, etc)My question is is this good design? I decided not to use getters and setters. It would just bloat the code for no reason (at least I can't see one).All that being said, for some reason this smells like a bad code to me (not sure why), but I don't really see any other way of implementing it without doing an overkill, given it's role in the program.EDIT: Here is the full code of the root class. All the other classes have the same structure:namespace SaveManipulator.GameData{[Serializable]public class CustomFile{    //version = 7    public Value<uint> saveFileVersion;    //ecd    public ECD ecd;    //food    public Food food;    //drink    public Drink drink;    //inventory    public Stack[] inventory;    //selectedSlot    public Value<int> selectedSlot;    //bag    public Stack[] bag;    //craftedList    public HashSet<string> craftedList;    //spawnPoints    public List<Vector3Di> spawnPoints;    //SpawnKey    public Value<long> SpawnKey;    //notSaved = true    public Value<bool> randomBoolean;    //notSaved = 0    public Value<short> randomShort;    //bLoaded    public Value<bool> bLoaded;    //lastPosition    public Vector3Di lastPosition;    //id    public Value<int> id;    //droppedPosition    public Vector3Di droppedPosition;    //kills    public Value<int> kills;    //fKills    public Value<int> fKills;    //deaths    public Value<int> deaths;    //score    public Value<int> score;    //equipment    public Equipment equipment;    //unlockedList    public List<string> unlockedList;    //notSaved = 1    public Value<ushort> randomUShort;    //marker    public Vector3Di marker;    //favorites    public Equipment favorites;    //experience    public Value<uint> experience;    //level    public Value<int> level;    //bCrouched    public Value<bool> bCrouched;    //cdata    public Cdata cdata;    //favoriteList    public List<string> favoriteList;    //J    public Skills skills;    //totalItems    public Value<uint> totalItems;    //distance    public Value<float> distance;    //life    public Value<float> life;    //waypoints    public Waypoints waypoints;    //skillPoints    public Value<int> skillPoints;    //quests    public Quests quests;    //deathTime    public Value<int> deathTime;    //currentL    public Value<float> currentL;    //bDead    public Value<bool> bDead;    public CustomFile Clone()    {        Stream stream = new FileStream(CustomFile , FileMode.Create, FileAccess.Write, FileShare.None);        IFormatter formatter = new BinaryFormatter();        formatter.Serialize(stream, this);        stream.Close();        stream = new FileStream(CustomFile, FileMode.Open, FileAccess.Read, FileShare.None);        PlayerDataFile clone = (PlayerDataFile)formatter.Deserialize(stream);        stream.Close();        File.Delete(CustomFile);        return clone;    }    public void Read(string path)    {        BinaryReader reader = new BinaryReader(new FileStream(path, FileMode.Open));        if (reader.ReadChar() == 'd' && reader.ReadChar() == 't' && reader.ReadChar() == 's' &&            reader.ReadChar() == '\0')        {            saveFileVersion = new Value<uint>((uint)reader.ReadByte());            ecd = new ECD();            ecd.Read(reader);            food = new Food();            food.Read(reader);            drink = new Drink();            drink.Read(reader);            inventory = Stack.Read(reader);            selectedSlot = new Value<int>((int)reader.ReadByte());            bag = Stack.Read(reader);            //num            int craftedListLength = (int)reader.ReadUInt16();            craftedList = new HashSet<string>();            for (int i = 0; i < craftedListLength; i++)            {                craftedList.Add(reader.ReadString());            }            //b            byte spawnPointsCount = reader.ReadByte();            spawnPoints = new List<Vector3Di>();            for (int j = 0; j < (int)spawnPointsCount; j++)            {                Vector3Di spawnPoint = new Vector3Di();                spawnPoint.x = new Value<int>(reader.ReadInt32());                spawnPoint.y = new Value<int>(reader.ReadInt32());                spawnPoint.z = new Value<int>(reader.ReadInt32());                spawnPoints.Add(spawnPoint);            }            spawnKey = new Value<long>(reader.ReadInt64());            randomBoolean = new Value<bool>(reader.ReadBoolean());            randomShort = new Value<short>(reader.ReadInt16());            bLoaded = new Value<bool>(reader.ReadBoolean());            lastPosition = new Vector3Di();            lastPosition.x = new Value<int>(reader.ReadInt32());            lastPosition.y = new Value<int>(reader.ReadInt32());            lastPosition.z = new Value<int>(reader.ReadInt32());            lastPosition.heading = new Value<float>(reader.ReadSingle());            id = new Value<int>(reader.ReadInt32());            droppedPosition = new Vector3Di();            droppedPosition.x = new Value<int>(reader.ReadInt32());            droppedPosition.y = new Value<int>(reader.ReadInt32());            droppedPosition.z = new Value<int>(reader.ReadInt32());            kills = new Value<int>(reader.ReadInt32());            fKills = new Value<int>(reader.ReadInt32());            deaths = new Value<int>(reader.ReadInt32());            score = new Value<int>(reader.ReadInt32());            equipment = Equipment.Read(reader);            //num            int count = (int)reader.ReadUInt16();            unlockedList = new List<string>();            for (int k = 0; k < count ; k++)            {                unlockedList .Add(reader.ReadString());            }            randomUShort = new Value<ushort>(reader.ReadUInt16());            marker = new Vector3Di();            marker.x = new Value<int>(reader.ReadInt32());            marker.y = new Value<int>(reader.ReadInt32());            marker.z = new Value<int>(reader.ReadInt32());            favorites = Equipment.Read(reader);            experience = new Value<uint>(reader.ReadUInt32());            level = new Value<int>(reader.ReadInt32());            bCrouched = new Value<bool>(reader.ReadBoolean());            cdata = new Cdata();            cdata.Read(reader);            //num            int favoriteListSize = (int)reader.ReadUInt16();            favoriteList = new List<string>();            for (int l = 0; l < favoriteListSize; l++)            {                favoriteList.Add(reader.ReadString());            }            //num2            int size = (int)reader.ReadUInt32();            skills = new Skills();            skills.Read(reader);            totalItems = new Value<uint>(reader.ReadUInt32());            distance = new Value<float>(reader.ReadSingle());            life = new Value<float>(reader.ReadSingle());            waypoints = new Waypoints();            waypoints.Read(reader);            skillPoints = new Value<int>(reader.ReadInt32());            quests = new Quests();            quests.Read(reader);            deathTime = new Value<int>(reader.ReadInt32());            currentL = new Value<float>(reader.ReadSingle());            bDead = new Value<bool>(reader.ReadBoolean());            //irelevant bytes            reader.ReadByte();            reader.ReadBoolean();            reader.Close();        }        else        {            throw new IOException(Save file corrupted!);        }    }    public void Write(string path)    {        BinaryWriter writer = new BinaryWriter(new FileStream(path, FileMode.Create));        writer.Write('d');        writer.Write('t');        writer.Write('s');        writer.Write((byte)0);        writer.Write((byte)saveFileVersion.Get());        ecd.Write(writer);        food.Write(writer);        drink.Write(writer);        Stack.WriteItemStack(writer, inventory);        writer.Write((byte)selectedSlot.Get());        Stack.WriteItemStack(writer, bag);        writer.Write((ushort)craftedList.Count);        HashSet<string>.Enumerator enumerator = craftedList.GetEnumerator();        while (enumerator.MoveNext())        {            writer.Write(enumerator.Current);        }        writer.Write((byte)spawnPoints.Count);        for (int i = 0; i < spawnPoints.Count; i++)        {            writer.Write(spawnPoints[i].x.Get());            writer.Write(spawnPoints[i].y.Get());            writer.Write(spawnPoints[i].z.Get());        }        writer.Write(selectedSpawnKey.Get());        writer.Write(randomBoolean.Get());        writer.Write(randomShort.Get());        writer.Write(bLoaded.Get());        writer.Write((int)lastPosition.x.Get());        writer.Write((int)lastPosition.y.Get());        writer.Write((int)lastPosition.z.Get());        writer.Write(lastPosition.heading.Get());        writer.Write(id.Get());        writer.Write(droppedPosition.x.Get());        writer.Write(droppedPosition.y.Get());        writer.Write(droppedPosition.z.Get());        writer.Write(kills.Get());        writer.Write(zKills.Get());        writer.Write(deaths.Get());        writer.Write(score.Get());        equipment.Write(writer);        writer.Write((ushort)unlockedList.Count);        List<string>.Enumerator enumerator2 = unlockedList.GetEnumerator();        while (enumerator2.MoveNext())        {            writer.Write(enumerator2.Current);        }        writer.Write(randomUShort.Get());        writer.Write(marker.x.Get());        writer.Write(marker.y.Get());        writer.Write(marker.z.Get());        favorites.Write(writer);        writer.Write(experience.Get());        writer.Write(level.Get());        writer.Write(bCrouched.Get());        cdata.Write(writer);        writer.Write((ushort)favoriteList.Count);        List<string>.Enumerator enumerator3 = favoriteList.GetEnumerator();        while (enumerator3.MoveNext())        {            writer.Write(enumerator3.Current);        }        skills.Write(writer);        writer.Write(totalItems.Get());        writer.Write(distance.Get());        writer.Write(life.Get());        waypoints.Write(writer);        writer.Write(skillPoints.Get());        quests.Write(writer);        writer.Write(deathTime.Get());        writer.Write(currentL.Get());        writer.Write(bDead.Get());        writer.Write((byte)88);        writer.Write(true);        writer.Close();    }    public CustomFile(string path)    {        Read(path);    }}}Since the code is mostly copied from the source of the game, I obfuscated it a little bit, that's why some names may look vague. Also Value<Type> is a wrapper class used to pass around value types while keeping their reference without explicitly having to think about it. That way the user can change bits of the file easier. I don't really see how I could partially save the file. Save files are usually from 4kB to (my estimate) 10kB. They aren't that big.
Design of a storage object - object used soley to store data
design;object oriented;object oriented design