Wednesday, October 19, 2011

Refactoring to expose an ObservableCollection as a ReadOnlyObservableCollection property

I was working with ObservableCollection<> objects and as the code/design/architecture matured, I wanted to expose them as true read-only properties.
This is what my initial code looked like:

//This is what I had
private ObservableCollection<int> _myIntCollection;
publ ObservableCollection<int> myIntCollection
{
//This does not give me much other than not being able to create a new myIntCollection. I can add/delete items from the collection
    get
    {
        return _myIntCollection;
    }
}
//...Code that creates a new _myIntCollection who knows where and how many times

Intellisense showed me ReadOnlyObservableCollection<> along with ObservableCollection<> and that looked like just what I wanted!

//First change
private ObservableCollection<int> _myIntCollection;
public ReadOnlyObservableCollection<int> myIntCollection
{
    get
    {
//Cool: now my presenters/clients cannot modify the collection also
//But: I create a new collection on every read,
//and that can affect the performance as well as cause other unexpected issues
        return new ReadOnlyObservableCollection<int>(_myIntCollection);
    }
}
//...Code that creates a new _myIntCollection who knows where and how many times

I figured that it is not neat to create a new instance of a readonly collection every time I want to access the property, and found this post:
ReadOnlyObservableCollection anti-pattern
I liked the idea of creating the new readonly collection when I create my base observable collection, but I did not want find all references and add code to every "new" statement.
A more manageable way of refactoring to expose an ObservableCollection as a ReadOnlyObservableCollection is to convert the base ObservableCollection object also into a property that initializes the ReadOnlyObservableCollection object whenever the base object is set:

//Much better, and I don't have to worry about
//"who knows where and how many times" _myIntCollection is created in my code

//The real writable collection
private ObservableCollection<int> _w_myIntCollection;

//My existing code uses _myIntCollection to create the collection and I don't want to change that
private ObservableCollection<int> _myIntCollection
{
    get
    {
        return _w_myIntCollection;
    }
    set
    {
        _w_myIntCollection = value;
//with this, whereever there is _myIntCollection = new ObservableCollection in the existing code,
//it will create my readonly collection also now
        _r_myIntCollection = new ReadOnlyObservableCollection<int>(_w_myIntCollection);
    }
}
//my read-only collection used within the class
private ReadOnlyObservableCollection<int> _r_myIntCollection;

//read-only property so that presenters/clients cannot create a new read-only collection
public ReadOnlyObservableCollection<int> myIntCollection
{
    get
    {
        return _r_myIntCollection;
    }
}
//...Code that creates a new _myIntCollection who knows where and how many times

No comments:

Post a Comment