...by having the setter of the Name
property raise an event...
Do you mean something like this?
c1.Name = "Sofia";
NameChangedEventHandler handler = NameChangedEvent;
if (handler != null)
{
handler(c1, new NameChangedEventArgs("Sophie", "Sophia"));
}
Is this what you mean by having the setter raise an event? If so, then I would suggest moving this to the Name property setter of the Cat class. There's no reason to require the setters to raise the event like this. It should be done implicitly when the name of the Cat changes through the public property.
To me, this is an elegant solution; it just doesn't conform to the way Dictionary collections work. I don't know that that's a problem per se, but it does tightly couple the Cats collection to the Cat class.
Keep in mind that you'll probably want to implement many of the same interfaces that the generic Dictionary class does. Otherwise, the Cats collection will resemble a Dictionary in some ways, but not fully.
EDIT: This is in response to your comment. I hope that I can more clearly convey my thoughts. My intent is to improve your design.
I agree that, in general, events do provide a looser level of coupling. However, in this case, the Cats collection is still tightly coupled with the Cat class because the collection is registering with a specific type of event exposed by a specific type of class.
So how can this be improved?
A straightforward way to improve this is to have the Cat class implement an event that is defined in an interface. .NET provides such an interface for this express purpose - the INotifyPropertyChanged interface in the System.ComponentModel namespace. By implementing this interface in the Cat class, this would allow the Cats collection wrapper to be defined like this:
class Cats
{
private Dictionary<string, INotifyPropertyChanged> m_dic =
new Dictionary<string, INotifyPropertyChanged>();
public void Add(INotifyPropertyChanged obj)
{
m_dic.Add(obj.Name, obj);
}
public void Remove(string name)
{
m_dic.Remove(name);
}
public INotifyPropertyChanged this[string name]
{
get { return m_dic[name]; }
}
}
See the improvement? The collection is more flexible now. It can hold any type that implements the INotifyPropertyChanged interface. In other words, it is not tied to the Cat class anymore.
However, it still has the requirement that whatever value is stored in the dictionary implement a Name property (see the Add() method), so there is still some work to be done.
Ultimately, you are wanting the collection to hold objects that provide a string property to be used as the key value. The solution is to define this as an interface as well.
public interface INotificationKey : INotifyPropertyChanged
{
string Key { get; set; }
}
Notice that the INotificationKey interface inherits from the INotifyPropertyChanged interface, which allows the collection wrapper to be defined like this:
class NotificationDictionary
{
private Dictionary<string, INotificationKey> m_dic =
new Dictionary<string, INotificationKey>();
public void Add(INotificationKey obj)
{
m_dic.Add(obj.Key, obj);
}
public void Remove(string key)
{
m_dic.Remove(key);
}
public INotificationKey this[string key]
{
get { return m_dic[key]; }
}
}
This is a substantially more flexible solution. But it still falls short because it does not fully act like a Dictionary should. For example, as defined, the NotificationDictionary class cannot be used in a foreach iteration since it does not implement the IEnumerable<> interface.
To qualify as a truly elegant solution, the collection should behave like a Dictionary. This will require a little more effort on the front end, but on the back end, you'd have a solution that would be flexible enough to adapt to a variety of situations.