I recently released my very first package to NuGet. Enter MutableObject, used to create and manage CLR-objects that you can track state of with a few simple calls. Ever came into a situation where you wanted to know what properties has changed since some point in your code? To do so, you needed to rewrite every setter in the entire class, and that’s simply painful to do when this is a task that could be solved automatically. MutableObject solves this, but let me just illustrate this problem first:
public interface IContact { int Id { get; set; } string Name { get; set; } string Email { get; set; } } public class Contact : IContact { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } } public class ContactRepo { public IContact GetContact(int id) { // Lots of db-code to get the contact. Not LinqToSql or Entities, // plain SQL here. if(!result) return null; return new Contact { Name = name, Email = email, Id = id }; } public void Update(IContact contact) { var dbContact = GetContact(contact.Id); var qb = new StringBuilder("UPDATE Contacts SET "); // Get all the changed properties and loop trough and add // the property to the update-query. qb.Append(" WHERE Id = ").Append(contact.Id); } }
Now this is just a dummy-problem that I constructed to illustrate how MutableObject might be used, but I think this shows it pretty well. For instance, I’m using concatenation to construct a SQL-query (which you simply shouldn’t do in this day and age). Anyway, my point was to talk about MutableObject, so, in VisualStudio fire up the nuget package manager and run “Install-Package MutableObject”. Then, let’s change our GetContact-method a tiny bit to enable the use of MutableObject.
public IContact GetContact(int id) { // Lots of db-code to get the contact. Not LinqToSql or Entities, // plain SQL here. if(!result) return null; var contact = new Contact { Name = name, Email = email, Id = id }; return Mutate.CreateMutableObject<IContact>(contact); }
Now, what we did was to make sure that the GetContact-method returns a MutableObject and not just a simple Contact. The MutableObject returned implement all of IContact (as long as there are only properties), so the object returned from GetContact can be used just like normal. This is called creating a MutableObject with a base-object. The base-object is the contact we passed in as it’s only parameter. It’s also possible to create a MutableObject without a base-object, but if you do, and you try to read a property without setting it first, it will throw an exception. If a MutableObject is created with a base-object (i.e. it is “bound”), all changes done to the MutableObject will be reflected in the base-object, however, you should be careful about changing the base-object after the MutableObject is created, as that is something I have never tried to do, and I have no idea of what the result will be.
Once you have a MutableObject (which you can confirm by calling Mutate.IsMutable(object obj)) you can essentially do two things with it, you can use it like any normal .Net classes, and set/get properties as you like, and you can get a list over the properties that has changed since the MutableObject was created. You can also check if a property/properties is set with the Mutate.PropertiesIsSet(object obj, params string[] propertyNames), however, when using bound items this will always return true.
Now, let’s update our Update-method so that it actually builds the query.
public void Update(IContact contact) { var dbContact = GetContact(contact.Id); var qb = new StringBuilder("UPDATE Contacts SET "); var props = Mutate.GetChangedProperties(contact); foreach(var prop in props) qb.Append(prop.Key).Append(" = \"").Append(prop.Value).Append("\", "); qb.Remove(qb.Length - 3, 3); qb.Append(" WHERE Id = ").Append(contact.Id); }
And there you have it! Ofcause MutableObject could be inproved (and I plan to do so in the feature). One of the things I plan to implement is the ability to reset the MutableObject, or create a new MutableObject with another mutable-object as a snapshot without applying changes back to the original MutableObject, but that’s all for another time. Hope you can find some use for it . Leave me a comment if there is anything you want to ask or don’t understand.
Later.
