Passing object with null member

N

news

..Net 2.0

Hi, I'm getting a nullreferenceexception when calling a function from a
worker thread:

private void CallbackProc(string response, Exception ex)
{
if (this.InvokeRequired)
{
this.Invoke(new MyCallback(CallbackProc), new object[] {
response, ex });
}
else
{
// do stuff here on the ui thread
}
}

It is true that ex is indeed null in some calls of CallbackProc, but
not always. The exception is thrown whenever ex is indeed null.
However, the documentation doesn't say that I can't pass null in an
Invoke (indeed it seems to say the opposite). So, I tried it out with a
fresh project but this time from one thread. (I.e. no worker thread.)
Ok, it was a hack because I replaced the "this.Invokerequired" with a
flag to ensure it only looped once. Anyway, the point is that it
worked: Invoke was happy to have a null argument in the object array.

My final test was to enclose the Invoke in a try catch. Surprisingly,
although the exception is still thrown, the Invoke call is still made
and works exactly as I want it to! Weird!

I could leave it with the try catch but that's horrible. So, can
someone point me in the right direction please?

TIA
 
J

Jon Shemitz

Hi, I'm getting a nullreferenceexception when calling a function from a
worker thread:

private void CallbackProc(string response, Exception ex)
{
if (this.InvokeRequired)
{
this.Invoke(new MyCallback(CallbackProc), new object[] {
response, ex });
}
else
{
// do stuff here on the ui thread
}
}

This should be valid. Is it the Invoke that's throwing the exception,
or is it simply relaying an exception thrown by the "do stuff here on
the ui thread" code?
 
N

news

Jon said:
This should be valid. Is it the Invoke that's throwing the exception,
or is it simply relaying an exception thrown by the "do stuff here on
the ui thread" code?

It is the Invoke that's complaining, and in particular the fact that ex
is null. If I force populate ex with a new Exception object (the
problem, of course, occurs whatever object type I choose) just before
the Invoke, it works without complaining. Very odd indeed.
 
J

Jon Skeet [C# MVP]

It is the Invoke that's complaining, and in particular the fact that ex
is null. If I force populate ex with a new Exception object (the
problem, of course, occurs whatever object type I choose) just before
the Invoke, it works without complaining. Very odd indeed.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
J

Jon Shemitz

It is the Invoke that's complaining, and in particular the fact that ex
is null. If I force populate ex with a new Exception object (the
problem, of course, occurs whatever object type I choose) just before
the Invoke, it works without complaining. Very odd indeed.

Have you tried commenting out the "do stuff here on the ui thread"
code? The code below works just fine, for me. If I uncomment the
`throw new NullReferenceException()` line, I do get a
NullReferenceException on the Invoke.

using System;
using System.Windows.Forms;
using System.Threading;

namespace InvokeIssue
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(delegate
{
CallbackProc("In thread", null);
});
}

delegate void MyCallback(string response, Exception ex);

private void CallbackProc(string response, Exception ex)
{
if (this.InvokeRequired)
{
this.Invoke(new MyCallback(CallbackProc), new object[]
{
response, ex
});
}
else
{
// do stuff here on the ui thread
//throw new NullReferenceException();
MessageBox.Show(
String.Format("response = {0}\nex is {1}null",
response, ex == null ? "" : "not "),
"CallbackProc");
}
}
}
}
 
B

Bruce Wood

It is the Invoke that's complaining, and in particular the fact that ex
is null. If I force populate ex with a new Exception object (the
problem, of course, occurs whatever object type I choose) just before
the Invoke, it works without complaining. Very odd indeed.

Don't forget that if your callback method fails when you pass it an ex
== null, then the final exception you get will be from the Invoke, with
the true exception that caused the problem as its InnerException.

I've run across this many times. I look at the exception and think,
"Oh, I've screwed up the Invoke," when in fact I haven't: the error is
in the code that was Invoked, and it's just the way that exceptions are
handled across an invocation that makes it look otherwise.
 
N

news

Bruce said:
Don't forget that if your callback method fails when you pass it an ex
== null, then the final exception you get will be from the Invoke, with
the true exception that caused the problem as its InnerException.

I've run across this many times. I look at the exception and think,
"Oh, I've screwed up the Invoke," when in fact I haven't: the error is
in the code that was Invoked, and it's just the way that exceptions are
handled across an invocation that makes it look otherwise.

Bingo - problem solved! InnerException was null, but the Invoke was
indeed complaining about an a null exception in the _else_ statement.
(The debugger doesn't help because I can't "step into" the invoke even
with F11 - it's always the Invoke that throws the exception in the IDE.
Maybe I'm not using it right?) I pared the code down until I had the
bare essentials throwing the exception. My schoolboy mistake was then
obvious. :) For anyone else following this, here's the bug. Thanks to
Jon, Jon and Bruce for your help.



using System;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApp
{
public delegate void MyCallback(Exception ex);

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Click(object sender, EventArgs e)
{
Worker worker = new Worker(new MyCallback(CallbackProc));
Thread thread = new Thread(new
ThreadStart(worker.FireItUp));
thread.Start();
}

public void CallbackProc(Exception ex)
{
if (this.InvokeRequired)
{
this.Invoke(new MyCallback(CallbackProc), new object[]
{ ex });
}
else
{
// The following line is the bug as ex can be null.
D'oh!
Console.WriteLine(ex.Message);
}
}
}

public class Worker
{
public MyCallback _callback;

public Worker(MyCallback callback)
{
_callback = callback;
}

public void FireItUp()
{
_callback(null);
}
}
}
 
N

news

Bruce said:
Don't forget that if your callback method fails when you pass it an ex
== null, then the final exception you get will be from the Invoke, with
the true exception that caused the problem as its InnerException.

I've run across this many times. I look at the exception and think,
"Oh, I've screwed up the Invoke," when in fact I haven't: the error is
in the code that was Invoked, and it's just the way that exceptions are
handled across an invocation that makes it look otherwise.

Bingo - problem solved! InnerException was null, but the Invoke was
indeed complaining about an a null exception in the _else_ statement.
(The debugger doesn't help because I can't "step into" the invoke even
with F11 - it's always the Invoke that throws the exception in the IDE.
Maybe I'm not using it right?) I pared the code down until I had the
bare essentials throwing the exception. My schoolboy mistake was then
obvious. :) For anyone else following this, here's the bug. Thanks to
Jon, Jon and Bruce for your help.



using System;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApp
{
public delegate void MyCallback(Exception ex);

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Click(object sender, EventArgs e)
{
Worker worker = new Worker(new MyCallback(CallbackProc));
Thread thread = new Thread(new
ThreadStart(worker.FireItUp));
thread.Start();
}

public void CallbackProc(Exception ex)
{
if (this.InvokeRequired)
{
this.Invoke(new MyCallback(CallbackProc), new object[]
{ ex });
}
else
{
// The following line is the bug as ex can be null.
D'oh!
Console.WriteLine(ex.Message);
}
}
}

public class Worker
{
public MyCallback _callback;

public Worker(MyCallback callback)
{
_callback = callback;
}

public void FireItUp()
{
_callback(null);
}
}
}
 

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