Reputation: 13
Not sure what exactly is going on here, but seems like in .NET 1.1 an uninitialized event delegate can run without issues, but in .NET 2.0+ it causes a NullReferenceException. Any ideas why. The code below will run fine without issues in 1.1, in 2.0 it gives a NullReferenceException. I'm curious why does it behave differently? What changed?
Thanks
eg
class Class1
{
public delegate void ChartJoinedRowAddedHandler(object sender);
public static event ChartJoinedRowAddedHandler ChartJoinedRowAdded;
public static DataTable dt;
public static void Main()
{
dt = new DataTable();
dt.RowChanged += new DataRowChangeEventHandler(TableEventHandler);
object [] obj = new object[]{1,2};
dt.Columns.Add("Name");
dt.Columns.Add("Last");
dt.NewRow();
dt.Rows.Add(obj);
}
private static void TableEventHandler(object sender, DataRowChangeEventArgs e)
{
ChartJoinedRowAdded(new object());
}
}
Upvotes: 1
Views: 1199
Reputation: 155832
The way events work hasn't really changed from 1.1 to 2
Although the syntax looks like normal aggregation it really isn't:
dt.RowChanged += TableEventHandler;
dt.RowChanged += null;
dt.RowChanged += delegate (object sender, DataRowChangeEventArgs e) {
//anon
};
Will fire TableEventHandler
and then the delegate - the null is just skipped.
You can use null to clear events, but only inside the event firing class:
this.MyEvent = null;
If nothing subscribes your event will be null - see soraz's answer. The DataTable
class will contain a similar check and won't fire the event if there are no subscribers.
The standard pattern is:
//events should just about always use this pattern: object, args
public static event EventHandler<MyEventArgs> ChartJoinedRowAdded;
//inheriting classes can override this event behaviour
protected virtual OnChartJoinedRowAdded() {
if( ChartJoinedRowAdded != null )
ChartJoinedRowAdded( this, new MyEventArgs(...) );
}
Upvotes: 0
Reputation: 6756
The eventhandler system is basically just a list of functions to call when a given event is raised.
It initializes to the "null" list, and not the empty list, so you need to do
if (ChartJoinedRowAdded != null)
ChartJoinedRowAdded(new object())
Upvotes: 1
Reputation: 1063864
[updated] AFAIK, there was no change here to the fundamental delegate handling; the difference is in how DataTable behaves.
However! Be very careful using static events, especially if you are subscribing from instances (rather than static methods). This is a good way to keep huge swathes of objects alive and not be garbage collected.
Running the code via csc from 1.1 shows that the general delegate side is the same - I think the difference is that the DataTable code that raises RowChanged was swallowing the exception. For example, make the code like below:
Console.WriteLine("Before");
ChartJoinedRowAdded(new object());
Console.WriteLine("After");
You'll see "Before", but no "After"; an exception was thrown and swallowed by the DataTable.
Upvotes: 1