-1

I wrote a code that read all the items from a json that contains all the configuration of my application. In this code I've a property called obj:

public static SuperModel obj
{
    get
    {
        string json = File.ReadAllText(SettingsConfig.ConfigFilePath);
        var jsonObj = JsonConvert.DeserializeObject<SuperModel>(json);
        return jsonObj;
    }
}

SuperModel is the class model that contains instance of other classes. What I'm trying to achieve is update the json value and then call another method that should overwrite the file with the new json, like this:

Settings.obj.GeneralSettings.Language = "english";
Settings.Save();

But I've a problem, how can I monitor the change on obj, for example in this case I've updated the Language property of GeneralSettings -> SuperModel class, is possible store the updated object with Save() method that overwrite the file? I never encountered a similar situation.

How can I solve this?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Unchained
  • 187
  • 8
  • You don't need to detect changes if you're going to serialize the object to file again: if it's the same, nothing changes (except for the last modified date of the file), and if it's different, the file gets updated. What _exactly_ do you need this functionality for, and what did your research show? See for example [What is the best practice to check if an object is changed?](http://stackoverflow.com/questions/2071482/what-is-the-best-practice-to-check-if-an-object-is-changed). – CodeCaster Sep 27 '16 at 12:57
  • @CodeCaster I need to pass the updated object to the file for update the json file, that's why I need to detect change – Unchained Sep 27 '16 at 12:59
  • Check this question: http://stackoverflow.com/questions/2246777/raise-an-event-whenever-a-propertys-value-changed – Bassie Sep 27 '16 at 12:59
  • @CodeCaster what is not clear? – Unchained Sep 27 '16 at 13:01

3 Answers3

2

The problem you are trying to solve primarily is not about how to detect changes (which is well described in the answer linked by CodeCaster). The issue here is that your design is substantially flawed.

You are actually abusing a property to do what a method should do. Your property behaves as a generator of data, returning a new instance each time it is called (despite they would be the same from a value perspective). You never store the deserialized settings anywhere permanently, so it's not surprising there's no straightforward way to implement the Save() method.

Decouple your code and achieve a usage pattern like this:

Settings.LoadFromConfig();

… do whateever changes you need here …
Settings.MyConfig.GeneralSettings.Language = "english";

Settings.SaveToConfig();

The LoadFromConfig and SaveFromConfig methods should work with a SuperModel property, which can be simply declared like this:

public SuperModel MyConfig { get; private set; }

(The private setter ensures noone except the Settings class can create a new config instance.)

The actual implementation of LoadFromConfig and SaveFromConfig should be easy for you already.

Side note: It seems your Settings class is static. While it might make sense, it would generally be better to work rather work with an instance, although being a singleton.

Community
  • 1
  • 1
Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
  • @Unchained My code? It's your code ;) Go ahead and implement the `SaveToConfig` method. It's trivial, the opposit of a load which you've already implemented. – Ondrej Tucny Sep 27 '16 at 13:50
1

You're asking the wrong question. You don't want to "detect object updates", you want to keep a reference to a local variable that goes out of scope at your current return statement.

In order to do this, load the settings file only once, for example in a static constructor:

private static SuperModel _settingsObject;

static Settings
{
    string json = File.ReadAllText(SettingsConfig.ConfigFilePath);
    var jsonObj = JsonConvert.DeserializeObject<SuperModel>(json);
    _settingsObject = jsonObj;
}

Then when a caller obtains the settings object, simply return the loaded object:

public static SuperModel obj
{
    get
    {
        return _settingsObject;
    }
}

Now any caller who alters the SuperModel instance returned by Settings.obj, directly modifies the instance known by the Settings class. So the Save() method saves the modified instance:

public static void Save()
{
    string json = JsonConvert.SerializeObject(_settingsObject);
    File.WriteAllText(SettingsConfig.ConfigFilePath, json);
}

Also, look into naming guidelines for .NET. "obj" isn't really a useful identifier.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

When reading the object, assuming you have multiple nested chains, you can make a hash of the object properties and store it somewhere (e.g. an InitialHash property).

Whenever you want to check for changes, you can rehash the object properties and compare it against the InitialHash. This will only give you info that the object properties was changed, but not what exactly was changed.

Khalil Khalaf
  • 9,259
  • 11
  • 62
  • 104
Tamas Ionut
  • 4,240
  • 5
  • 36
  • 59