0

Is it possible to take following class and make it generic? It's a simple JSON file database that does simple Create and Update to task objects and propagates to a JSON file.

How do I make this generic? Do I put the generic type on the class or in the methods?

I want to be able to do this to any type of object.

public class TaskRepository
{
    string _filePath = Path.Combine(Directory.GetCurrentDirectory(), "dbFile.json");

    internal List<Task> Get()
    {
        var json = File.ReadAllText(_filePath);

        var tasks = JsonConvert.DeserializeObject<List<Task>>(json);

        return tasks;
    }

    internal Task Save(Task task)
    {
        List<Task> tasks = Get();
        if (tasks == null) tasks = new List<Task>();
        //Try and find incoming task
        var itemIndex = tasks.FindIndex(t => t.Id == task.Id);
        //Check if it exists
        if (itemIndex > 0)
        {
            //update existing task
            tasks[itemIndex] = task;
        }
        else
        {
            //add as new task
            int newIndex = tasks.Count + 1;
            task.Id = newIndex;
            task.DateCreated = DateTime.Now;
            tasks.Add(task);
        }
        //Update file
        WriteData(tasks);
        return task;
    }

    private bool WriteData(List<Task> tasks)
    {
        var json = JsonConvert.SerializeObject(tasks, Formatting.Indented);
        System.IO.File.WriteAllText(_filePath, json);

        return true;
    }

}

class Task
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Rod
  • 14,529
  • 31
  • 118
  • 230
  • The class name is TaskRepository. What would be the generic parameter(s) ? If you are planning to re-use this class for types other then Task, rename the class (JsonRepository ?) and make the class generic. (not the methods because all method parameters or return types are already of type Task or a collection of it.) – Oguz Ozgul Apr 27 '20 at 00:37
  • How do i handle the incrementing of the Ids and stamping the date time on Date Created column? Will those have to be done outside the class? But any class of mine for this purpose will have an id column and date created column. – Rod Apr 27 '20 at 00:55
  • 1
    You can have an abstract class, or a non-abstract base class for all your type if all of them has Id and DateCreated properties. Then you can have a constraint where T : MyBaseClass when defining your generic class – Oguz Ozgul Apr 27 '20 at 01:06

1 Answers1

0

Ok, with the help of the comments in OP I came up with the following. I used interface and type constraint.

public class TaskRepository<T> where T : IJsonDbFile
{
    string _filePath = Path.Combine(Directory.GetCurrentDirectory(), "dbFile.json");

    internal List<T> Get()
    {
        var json = File.ReadAllText(_filePath);

        var tasks = JsonConvert.DeserializeObject<List<T>>(json);

        return tasks;
    }
    internal DataTable GetDt(List<T> t)
    {
        return ConvertToDataTable(t);
    }
    internal T Save(T task)
    {
        List<T> tasks = Get();
        if (tasks == null) tasks = new List<T>();
        //Try and find incoming task
        var itemIndex = tasks.FindIndex(t => t.Id == task.Id);
        //Check if it exists
        if (itemIndex > 0)
        {
            //update existing task
            tasks[itemIndex] = task;
        }
        else
        {
            //add as new task
            int newIndex = tasks.Count + 1;
            task.Id = newIndex;
            task.DateCreated = DateTime.Now;
            tasks.Add(task);
        }
        //Update file
        WriteData(tasks);
        return task;
    }
    private bool WriteData(List<T> tasks)
    {
        var json = JsonConvert.SerializeObject(tasks, Formatting.Indented);
        System.IO.File.WriteAllText(_filePath, json);

        return true;
    }
    public DataTable ConvertToDataTable(IList<T> data)
    {
        //https://stackoverflow.com/a/21672842/139698
        PropertyDescriptorCollection properties =
           TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
}

class Task : IJsonDbFile
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }
}

public interface IJsonDbFile
{
    public int Id { get; set; }
    public DateTime DateCreated { get; set; }
}
Rod
  • 14,529
  • 31
  • 118
  • 230