I'm not sure whether my distaste for reflection is justified or not, but it feels ucky that I'm using reflection here.
I'm trying to make a very simple class which has a number of List<T>
where T : Model
with a load and save method.
The load method should:
- For every list,
- Open or create
"Data/(<T>)/"
- Sequentially load each file in the folder into memory by creating a new instance of
T
and callingDeserialize(Text)
The save method should:
- For every list,
- For every instance,
- Call
Serialize()
, and dump the result into"/Data/(<T>)/(ID)"
Originally, I began writing code to loop through my Member
list and my Game
list and then realised I was going to be writing duplicate code for every list of data and switched to having a List<IEnumerable<Model>>
and looping that and ended up having to use reflection. I was wondering if anyone can think of a way of achieving my goals without using reflection or having duplicate code for every type of model stored.
I'll attach my current completed class below. I don't mind doing string modelClassName = models.GetType().GenericTypeArguments.First().Name;
so much but it's the code:
Type modelType = models.GetType().GenericTypeArguments.First();
dynamic list = (this.GetType().GetRuntimeProperty(modelClassName + "s").GetValue(this));
dynamic loaded = Activator.CreateInstance(modelType);
loaded.Deserialize("");
list.Add(loaded);
That's really bothering me. It just feels wrong and suboptimal and I'm sure I'm not thinking this through properly.
Full code below:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Linq;
using Chess_Club.Models;
using Windows.Storage;
using System.Diagnostics;
namespace Chess_Club.DAL {
class ChessClubContext {
public List<IEnumerable<Model>> Models = new List<IEnumerable<Model>>();
public List<Game> Games = new List<Game>();
public List<Member> Members = new List<Member>();
private StorageFolder RootFolder;
private StorageFolder RootDataFolder;
public ChessClubContext() {
RootFolder = Windows.Storage.ApplicationData.Current.RoamingFolder;
Models.Add(Games);
Models.Add(Members);
}
public async void LoadData() {
RootDataFolder = await RootFolder.CreateFolderAsync("Data", CreationCollisionOption.OpenIfExists);
foreach (IEnumerable<Model> models in Models) {
string modelClassName = models.GetType().GenericTypeArguments.First().Name;
StorageFolder modelFolder = await RootDataFolder.CreateFolderAsync(modelClassName, CreationCollisionOption.OpenIfExists);
IReadOnlyList<StorageFile> files = await modelFolder.GetFilesAsync();
foreach (StorageFile file in files) {
// Some quick reflection to access the property... Saves duplicating this code n times for n as number of lists
Type modelType = models.GetType().GenericTypeArguments.First();
dynamic list = (this.GetType().GetRuntimeProperty(modelClassName + "s").GetValue(this));
dynamic loaded = Activator.CreateInstance(modelType);
loaded.Deserialize(""); // Pretend I'm actually loading the text around here, for now an empty string is fine.
list.Add(loaded);
}
}
}
public async void SaveData() {
foreach (IEnumerable<Model> models in Models) {
string modelClassName = models.GetType().GenericTypeArguments.First().Name;
StorageFolder modelFolder = await RootDataFolder.CreateFolderAsync(modelClassName, CreationCollisionOption.OpenIfExists);
foreach (Model model in models) {
StorageFile file = await modelFolder.CreateFileAsync(model.ID.ToString(), CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(file, model.Serialize());
}
}
}
}
}