Search code examples
c#disposeidisposable

Is Dispose() a good place to save data to disc?


I am creating a flat-file json-based database for learning purposes. I am changing the data contained by a JsonDatabase object but I want to save them to disc only after all the changes have been completed.

This is my current approach:

 public class UserMatch
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class JsonDatabase : IJsonDatabase, IDisposable
{

    private readonly FileStream _jsonDatabaseStream;

    private List<UserMatch> _userMatches;
    public List<UserMatch> UserMatches
    {
        get
        {
            if (_userMatches == default(List<UserMatch>))
            {
                string fileContent;
                using (var sr = new StreamReader(_jsonDatabaseStream))
                {
                    fileContent = sr.ReadToEnd();
                }
                _userMatches = JsonConvert.DeserializeObject<List<UserMatch>>(fileContent);
            }
            return _userMatches;
        }
        set { _userMatches = value; }
    }

    public JsonDatabase(string fileLocation)
    {
        _jsonDatabaseStream = File.Open(fileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
    }

    public void Dispose()
    {
        string serialisedJson = JsonConvert.SerializeObject(UserMatches);
        using (var sr = new StreamWriter(_jsonDatabaseStream))
        {
            sr.Write(serialisedJson);
        }
        _jsonDatabaseStream.Dispose();
    }
}

Is Dispose() the correct place to do this? Or should I rather create a separate Commit/Save method?


Solution

  • I think, in this particular case, a good pattern would be to:

    • Create a separate Commit method and a separate RollBack method.
    • Create a separate Close method that invokes Commit or Rollback depending on the semantics of closing your database.
    • Invoke your Close method from your dispose method so the database is closed when it is disposed.

    This way you're doing separation of concerns and clearly separating the semantics into each own method:

    • Rollback, Commit focus just on those operations and persist the data.
    • Close closes the database and defines the logic for what happens with open transactions on the event of that operation.
    • Dispose cleans up the object, among other things, by closing it.