...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.