stevebblee
stevebblee

Reputation: 13

Event Handler behavioral difference .net 1.1 vs 2.0 with null delegate

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

Answers (3)

Keith
Keith

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

Soraz
Soraz

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

Marc Gravell
Marc Gravell

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

Related Questions