Easier way to extend behavior?

L

Larry Lard

I want to create a class which is like a List<T>, except that whenever
a T is added, it raises an event.

Simple concept, I think, but I can't seem to find a simple execution.

Ideally I would inherit from List<T> and override an OnAdd method:

// This doesn't work
public class NotifyingList<T> : List<T>
{
public delegate void ItemAddedHandler(T item);
public event ItemAddedHandler ItemAdded;

void OnAdd(T item)
{
base.OnAdd(item);
ItemAdded(item);
}
}

But there isn't such an OnAdd method.

I could inherit from List<T> and *shadow* the Add(T) method, casting
down to the base class to do the actual adding and then raising the
event:

public class NotifyingList<T> : List<T>
{
public delegate void ItemAddedHandler(T item);
public event ItemAddedHandler ItemAdded;

new public void Add(T item)
{
((List<T>)this).Add(item);
ItemAdded(item);
}
}


But Shadowing Is Bad, and also any client of the class could:

static void Main(string[] args)
{
NotifyingList<String> foo = new NotifyingList<string>();
foo.ItemAdded += StringAdded;

foo.Add("apple");
foo.Add("banana");

// evil client!
((List<string>)foo).Add("pear");

Console.ReadLine();
}

static void StringAdded(string s)
{
Console.WriteLine(s);
}


Neatly sidestepping the event raising mechanism just by downcasting (or
is it upcasting).

I could keep a private List<T> myself, and make my public signature the
same as that of a List<T>, writing code to delegate every operation to
my private List<T>, with the addition of the event raising:

public class NotifyingList<T>
{
public delegate void ItemAddedHandler(T item);
public event ItemAddedHandler ItemAdded;

private List<T> items;

public void Add(T item)
{
items.Add(item);
ItemAdded(item);
}

public ReadOnlyCollection<T> AsReadOnly()
{
return items.AsReadOnly();
}

public int BinarySearch(T item)
{
return items.BinarySearch(item);
}

public void foo()
{
items.foo();
}

// etc
// etc
// for all 50 members
}


But this involves writing a huge amount of 'empty' code, simply to
achieve one very small end.

Thoughts?
 
B

Barry Kelly

Larry Lard said:
I want to create a class which is like a List<T>, except that whenever
a T is added, it raises an event.

Simple concept, I think, but I can't seem to find a simple execution.

Inherit from Collection<T> in the System.Collections.ObjectModel
namespace and override its InsertItem() method.

-- Barry
 
J

Joanna Carter [TeamB]

"Larry Lard" <[email protected]> a écrit dans le message de (e-mail address removed)...

|I want to create a class which is like a List<T>, except that whenever
| a T is added, it raises an event.

Look at the System.ComponentModel.BindingList<T> class, it does all that you
appear to want without any effort on your part :)

Joanna
 
J

John B

Larry said:
I want to create a class which is like a List<T>, except that whenever
a T is added, it raises an event.

But Shadowing Is Bad, and also any client of the class could:

static void Main(string[] args)
{
NotifyingList<String> foo = new NotifyingList<string>();
foo.ItemAdded += StringAdded;

foo.Add("apple");
foo.Add("banana");

// evil client!
((List<string>)foo).Add("pear");

Console.ReadLine();
}

In the case of downcasting to IList and therefore bypassing your add
method, you could explicitly implement IList.Add yourself and just chain
the call to your add method by casting.

I had the exact same problem and solved it by this method.

<...>

HTH
JB
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top