Always Read Generated Code

You might find treasure in there

January 17, 2018

This is one of my “A-ha” moments.

Consider how a lot of interfaces work - load an object from some remote system, make some property changes on the object, then save it back to the remote system. The pseudocode looks something like:

if (needToChangePropX == true)
{
    LogChange("PropX", obj.PropX, newPropXValue);
    obj.PropX = newPropXValue;
    objChanged = true; // To keep track if anything changed
}

if (needToChangePropY == true)
{
    LogChange("PropY", obj.PropY, newPropYValue);
    obj.PropY = newPropYValue;
    objChanged = true; // To keep track if anything changed
}

// And so on...

if (objChanged == true)
{
    obj.Save();
}

Besides just the general ugliness that has to come from checking all the values to determine if something applies or not, there are those three repetitive statements in the body of each if:

  1. Log something (because without logging debugging this thing is almost impossible, especially production problems).
  2. Change the actual thing you want to change.
  3. Mark that you have changed the list item.

That last piece is because you don’t want to save the list item on every property change. The round-trips and version history would kill you.

Even if you extract out everything to a method, you’re having to manually call that method for every property change.

The above works, but it sure is ugly (as interfacing with legacy systems often is).

But for interfaces that are based on service references or .edmx files in Entity Framework, there is a better way.

While researching something else, I actually was looking at the generated code in Reference.cs that gets created when doing a service reference…The first thing that caught my eye but wasn’t immediately useful is that all the classes in the generated code are partials – hmmm. More on that at the end. But the second thing that caught my eye was this:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")]
public string PropX
{
    get
    {
        return this._PropX;
    }
    set
    {
        this.OnPropXChanging(value);
        this._PropX = value;
        this.OnPropXChanged();
        this.OnPropertyChanged("PropX");
    }
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")]
private string _PropX;
partial void OnPropXChanging(string value);
partial void OnPropXChanged();

Well look at that. Every property in that generated context class raises OnChange events! At first, I thought I could use the partials and just override those for each property. But that is a lot of work. But see that this.OnPropertyChanged(“PropX”) at the end of the setter? THAT is interesting! Let’s go look at that:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")]
public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")]
protected virtual void OnPropertyChanged(string property)
{
    if ((this.PropertyChanged != null))
    {
        this.PropertyChanged(this, new global::System.ComponentModel.PropertyChangedEventArgs(property));
    }
}

It checks to see if the public PropertyChanged property has an event handler in it, and if it does, it calls it, passing in both the list item object itself (the list item’s current state after the change) and the property name that changed! Bingo!

So, in the loop where I am reading each item, I now just do this up front:

obj.PropertyChanged +=
    (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
    {
        var changedItem = (RemoteObjectType)sender;
        Log.Trace($"{e.PropertyName} changed to {changedItem.GetType().GetProperty(e.PropertyName).GetValue(changedItem, null)}");
        objChanged = true;
    };

Thanks to closures, the handler gets access to the objChanged flag1. And using reflection I can log based on the property name passed in.

So now the code to check and set a property simply looks like this:

if (needToChangePropX == true)
{
    obj.PropX = newPropXValue;
}

But we still get logging and the flag set telling us the list item has changed.

How cool is that?


  1. The other thoughts I have had but haven’t acted on are using the fact the class is a partial, which means I could create a second file for that class and implement something like the objChanged flag directly inside the remote item object itself, which would be much cleaner, I think.