473,406 Members | 2,273 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Why doesn't this compile?

I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?

class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}
public delegate void TestFailureEventHandler( string message );
public event TestFailureEventHandler TestFailure
{
add
{
// Do Something Here
TestFailure += value;
}
remove
{
TestFailure -= value;
// Do Something Here
}
}
public void SendFailureEvent()
{
if( TestFailure != null )
TestFailure( "Test Failure" );
}
}

Dec 6 '07 #1
10 1241
Scott S. <Sc****@community.nospamwrote:
I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?
A "field-like event" (like TestSuccess) declares both an event and a
variable - the variable is what gets referred to within the class, and
the event is what gets referred to outside the class.

Now, you've declared the TestFailure event but no corresponding
variable. Even if your code compiled, you'd get a stack overflow as
soon as you tried to subscribe to the event, because it would just call
the subscriber again. You need a normal variable to actually hold the
delegate instance, and *that's* what the body of add/remove and
SendFailureEvent should refer to.

See http://pobox.com/~skeet/csharp/events.html for more details.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk
Dec 6 '07 #2
On 6 Dec, 13:49, Scott S. <Sco...@community.nospamwrote:
I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?

class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}

public delegate void TestFailureEventHandler( string message );
public event TestFailureEventHandler TestFailure
{
add
{
// Do Something Here
TestFailure += value;
}
remove
{
TestFailure -= value;
// Do Something Here
}
}
public void SendFailureEvent()
{
if( TestFailure != null )
TestFailure( "Test Failure" );
}
}
Try the code below. I can't really describe why it goes wrong, it's
something to do with what the compiler does with access rights. I'm
sure someone will be able to explain

I added some thread safety features for good measure :)

using System;
namespace WindowsApplication34
{
class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}
public delegate void TestFailureHandler(object sender, EventArgs
e);

private event TestFailureHandler _testFailure;
private readonly object _eventLock = new object();

public event TestFailureHandler TestFailure
{
add
{
lock(_eventLock)
{
// Do Something Here
_testFailure += value;
}
}
remove
{
lock(_eventLock)
{
_testFailure -= value;
// Do Something Here
}
}
}
protected virtual void OnSendFailure(EventArgs e)
{
//Don't fire if null (which means no one is subscribed.
if (_testFailure != null)
{
//Fire the event
_testFailure(this,e);
}
}
public void SendFailureEvent()
{
OnSendFailure(new EventArgs()); //test
}
}
}
Dec 6 '07 #3
On 6 Dec, 14:14, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
Scott S. <Sco...@community.nospamwrote:
I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?

A "field-like event" (like TestSuccess) declares both an event and a
variable - the variable is what gets referred to within the class, and
the event is what gets referred to outside the class.

Now, you've declared the TestFailure event but no corresponding
variable. Even if your code compiled, you'd get a stack overflow as
soon as you tried to subscribe to the event, because it would just call
the subscriber again. You need a normal variable to actually hold the
delegate instance, and *that's* what the body of add/remove and
SendFailureEvent should refer to.

Seehttp://pobox.com/~skeet/csharp/events.htmlfor more details.

--
Jon Skeet - <sk...@pobox.com>http://www.pobox.com/~skeet Blog:http://www.msmvps.com/jon.skeet
World class .NET training in the UK:http://iterativetraining.co.uk
Good explanation :)
Dec 6 '07 #4
I kept looking ... there are very few examples out there using the custome
add/remove "properties" for event.
Most I've seen look just like my code, but I just came across one that
looked a little different and tried that ... it compiled.
The key bit is that declaring your own add and remove "properties" seems to
cause it to not create the usually implicit delegate list variable.
I just finished experimenting with my test code, and it does work.
I'm posting this "correct" usage of add/remove for others edification.

public delegate void TestFailureEventHandler( string message );
private TestFailureEventHandler TestFailureList;
public event TestFailureEventHandler TestFailure
{
add
{
// Do Something Here
TestFailureList += value;
}
remove
{
TestFailureList -= value;
// Do Something Here
}
}
public void SendFailureEvent()
{
if( TestFailureList != null )
TestFailureList( "Test Failure" );
}

Dec 6 '07 #5
Thanks Jon!

I _finally_ came across an example that did exactly what you're saying.
So I had found the solution, had just tested it and posted my own reply
before I saw your reply come in.
But thanks again, because I might not have ever found it since most examples
only show the event declaration witht he add and remove methods and many out
there have _exactly_ what I typed in them, which as you pointed out would do
BAD things.

"Jon Skeet [C# MVP]" wrote:
Scott S. <Sc****@community.nospamwrote:
I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?

A "field-like event" (like TestSuccess) declares both an event and a
variable - the variable is what gets referred to within the class, and
the event is what gets referred to outside the class.

Now, you've declared the TestFailure event but no corresponding
variable. Even if your code compiled, you'd get a stack overflow as
soon as you tried to subscribe to the event, because it would just call
the subscriber again. You need a normal variable to actually hold the
delegate instance, and *that's* what the body of add/remove and
SendFailureEvent should refer to.

See http://pobox.com/~skeet/csharp/events.html for more details.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk
Dec 6 '07 #6
I see what you did ... wrapped a public event interface around a private
event allowing the add/remove code to work before allowing the inner event to
function normally. It seems like that would work, but the solution of just
added a delegate list variable and using that is much cleaner.

Also, I like the thread protection ... I may use it inthe future but for now
I don't need it because all my objects are being created in the main thread.
I needed to override the add/remove to do a backround subscription to a
remote message queue so that I didn't have to do that when no objects wanted
events.

Hmmm ... on second thought, when the background object calls
SendSuccessEvent() I wonder if it will be on another thread?
If it is, I wonder what happens if an object tries to subscribe while it is
sending events?
I'm not sure, so I might just put in the thread protection just to be safe!

Thanks for the thought!

"DeveloperX" wrote:
On 6 Dec, 13:49, Scott S. <Sco...@community.nospamwrote:
I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?

class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}

public delegate void TestFailureEventHandler( string message );
public event TestFailureEventHandler TestFailure
{
add
{
// Do Something Here
TestFailure += value;
}
remove
{
TestFailure -= value;
// Do Something Here
}
}
public void SendFailureEvent()
{
if( TestFailure != null )
TestFailure( "Test Failure" );
}
}

Try the code below. I can't really describe why it goes wrong, it's
something to do with what the compiler does with access rights. I'm
sure someone will be able to explain

I added some thread safety features for good measure :)

using System;
namespace WindowsApplication34
{
class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}
public delegate void TestFailureHandler(object sender, EventArgs
e);

private event TestFailureHandler _testFailure;
private readonly object _eventLock = new object();

public event TestFailureHandler TestFailure
{
add
{
lock(_eventLock)
{
// Do Something Here
_testFailure += value;
}
}
remove
{
lock(_eventLock)
{
_testFailure -= value;
// Do Something Here
}
}
}
protected virtual void OnSendFailure(EventArgs e)
{
//Don't fire if null (which means no one is subscribed.
if (_testFailure != null)
{
//Fire the event
_testFailure(this,e);
}
}
public void SendFailureEvent()
{
OnSendFailure(new EventArgs()); //test
}
}
}
Dec 6 '07 #7
On 6 Dec, 14:58, Scott S. <Sco...@community.nospamwrote:
I see what you did ... wrapped a public event interface around a private
event allowing the add/remove code to work before allowing the inner event to
function normally. It seems like that would work, but the solution of just
added a delegate list variable and using that is much cleaner.

Also, I like the thread protection ... I may use it inthe future but for now
I don't need it because all my objects are being created in the main thread.
I needed to override the add/remove to do a backround subscription to a
remote message queue so that I didn't have to do that when no objects wanted
events.

Hmmm ... on second thought, when the background object calls
SendSuccessEvent() I wonder if it will be on another thread?
If it is, I wonder what happens if an object tries to subscribe while it is
sending events?
I'm not sure, so I might just put in the thread protection just to be safe!

Thanks for the thought!

"DeveloperX" wrote:
On 6 Dec, 13:49, Scott S. <Sco...@community.nospamwrote:
I need to have custom event subscribe and unsubscribe methods in some code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure doesn't.
It doesn't make any sense to me why.
Can anyone tell me what I'm either doing wrong, or what?
class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}
public delegate void TestFailureEventHandler( string message );
public event TestFailureEventHandler TestFailure
{
add
{
// Do Something Here
TestFailure += value;
}
remove
{
TestFailure -= value;
// Do Something Here
}
}
public void SendFailureEvent()
{
if( TestFailure != null )
TestFailure( "Test Failure" );
}
}
Try the code below. I can't really describe why it goes wrong, it's
something to do with what the compiler does with access rights. I'm
sure someone will be able to explain
I added some thread safety features for good measure :)
using System;
namespace WindowsApplication34
{
class TestEvent
{
public delegate void TestSuccessEventHandler( string message );
public event TestSuccessEventHandler TestSuccess;
public void SendSuccessEvent()
{
if( TestSuccess != null )
TestSuccess( "Test Success" );
}
public delegate void TestFailureHandler(object sender, EventArgs
e);
private event TestFailureHandler _testFailure;
private readonly object _eventLock = new object();
public event TestFailureHandler TestFailure
{
add
{
lock(_eventLock)
{
// Do Something Here
_testFailure += value;
}
}
remove
{
lock(_eventLock)
{
_testFailure -= value;
// Do Something Here
}
}
}
protected virtual void OnSendFailure(EventArgs e)
{
//Don't fire if null (which means no one is subscribed.
if (_testFailure != null)
{
//Fire the event
_testFailure(this,e);
}
}
public void SendFailureEvent()
{
OnSendFailure(new EventArgs()); //test
}
}
}- Hide quoted text -

- Show quoted text -
The thread protection is required because delegates are value type. So
if you have two threads trying to add handlers are the same time, the
following can happen:

Thread 1 reads the value of the delegate and sees it currently
contains sub 1.
Thread 2 reads the value of the delegate and sees it currently
contains sub 1.
Thread 1 adds its handler and now the delegate contains sub 1 and
thread 1's sub.
Thread 2 adds its handler and now the delegate contains sub 1 and
thread 2's sub.
The final value of the delegate could now be either sub1 and
thread1sub or sub1 and thread2sub depending on who wrote it back
first!
I don't know if there are any benefits to using a private delegate
over a private event. I've always used an event. I'm sure I had a
reason, but with all this knowledge stuff, after a while I remember
the how but not always the why :) Jon will know for certain *poke*
Dec 6 '07 #8
DeveloperX <nn*****@operamail.comwrote:
The thread protection is required because delegates are value type.
No they're not. They're immutable reference types.
So if you have two threads trying to add handlers are the same time, the
following can happen:

Thread 1 reads the value of the delegate and sees it currently
contains sub 1.
Thread 2 reads the value of the delegate and sees it currently
contains sub 1.
Thread 1 adds its handler and now the delegate contains sub 1 and
thread 1's sub.
Thread 2 adds its handler and now the delegate contains sub 1 and
thread 2's sub.
That much is true.
The final value of the delegate could now be either sub1 and
thread1sub or sub1 and thread2sub depending on who wrote it back
first!
Unfortunately, you didn't put enough thread-safety into OnSendFailure:

1) _testFailure can become null between the check and the fire
2) Because you don't take out a lock (or anything similar), there's no
guarantee you'll see the most recent value of the variable

See http://pobox.com/~skeet/csharp/threads/lockchoice.shtml for a
working example.
I don't know if there are any benefits to using a private delegate
over a private event. I've always used an event. I'm sure I had a
reason, but with all this knowledge stuff, after a while I remember
the how but not always the why :) Jon will know for certain *poke*
If it's private, I'd just use a delegate variable - why have both an
event and a variable when the variable is all that gets used anyway?
(There has to be a variable of some kind, otherwise nothing can get
stored.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk
Dec 6 '07 #9
On 6 Dec, 15:47, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
DeveloperX <nntp...@operamail.comwrote:
The thread protection is required because delegates are value type.

No they're not. They're immutable reference types.
So if you have two threads trying to add handlers are the same time, the
following can happen:
Thread 1 reads the value of the delegate and sees it currently
contains sub 1.
Thread 2 reads the value of the delegate and sees it currently
contains sub 1.
Thread 1 adds its handler and now the delegate contains sub 1 and
thread 1's sub.
Thread 2 adds its handler and now the delegate contains sub 1 and
thread 2's sub.

That much is true.
The final value of the delegate could now be either sub1 and
thread1sub or sub1 and thread2sub depending on who wrote it back
first!

Unfortunately, you didn't put enough thread-safety into OnSendFailure:

1) _testFailure can become null between the check and the fire
2) Because you don't take out a lock (or anything similar), there's no
guarantee you'll see the most recent value of the variable

Seehttp://pobox.com/~skeet/csharp/threads/lockchoice.shtmlfor a
working example.
I don't know if there are any benefits to using a private delegate
over a private event. I've always used an event. I'm sure I had a
reason, but with all this knowledge stuff, after a while I remember
the how but not always the why :) Jon will know for certain *poke*

If it's private, I'd just use a delegate variable - why have both an
event and a variable when the variable is all that gets used anyway?
(There has to be a variable of some kind, otherwise nothing can get
stored.)

--
Jon Skeet - <sk...@pobox.com>http://www.pobox.com/~skeet Blog:http://www.msmvps.com/jon.skeet
World class .NET training in the UK:http://iterativetraining.co.uk
Ah yes, very good point. Immutable reference type != value type. I
should of remembered that as I made the same mistake with strings when
I first started :)

I completely forgot to add locking on the raising of the event, my
bad :(
Dec 6 '07 #10
On Thu, 06 Dec 2007 05:49:01 -0800, Scott S. <Sc****@community.nospam>
wrote:
I need to have custom event subscribe and unsubscribe methods in some
code in
my application when I ran into this problem.
I created this simple class to demostrate the compile problem.
The use of TestSuccess event compiles, but the use of TestFailure
doesn't.
For what it's worth: if you are asking a question and there was some kind
of error, you really should be specific about the error.

Don't write "this compiles, this doesn't". Write the actual complete text
of the compiler error (sure, you could just post the CSxxxx number, but
not all of us have every number memorized :) ).

Same thing goes for exceptions, though that wasn't an issue in this thread.

You did get the information you need, mainly because in this case the
error was so simple and because someone like Jon was reading the code.
But that's not always going to be the case, and you should be in the habit
of posting better questions than the one you posted here. It will go a
long way toward you getting the information you want.

Pete
Dec 6 '07 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: James Thurley | last post by:
I'm trying to dynamically compile assemblies and cache them to disk, which seems to work fine. When the data I'm compiling from changes, I want to re-generate the assembly and use the new version....
4
by: Fernando Cuenca | last post by:
Hi, I'm trying to explicitly instantiate a template function using the following syntax: obj.template_func<type>(params); It compiles OK when used from a regular function, but it doesn't...
12
by: Rhino | last post by:
I am having an odd problem: the sqlj command on my system doesn't work. I am running DB2 (LUW) V8 (FP8) on WinXP. I haven't done an sqlj program since Version 6 of DB2 (LUW) so I checked the...
3
by: Karl Irvin | last post by:
When I click Debug>Compile, my modules seem to comple OK but the Compile menu choice doesn't gray out (to indicate compiling is not needed). The IsCompiles returns false, no matter how many times...
149
by: Christopher Benson-Manica | last post by:
(Followups set to comp.std.c. Apologies if the crosspost is unwelcome.) strchr() is to strrchr() as strstr() is to strrstr(), but strrstr() isn't part of the standard. Why not? --...
1
by: rvan | last post by:
Hi, I am trying to port one of my older MFC APP created in VC 6.0 to VC 7.0. Right away after starting the compile process, I get following errors and compilation stops. "d:\Microsoft .NET...
4
by: Eric Lilja | last post by:
Is this an invalid program? Doesn't compile on my system: #include <cstdio> class Why { enum TArch {LITTLE_ENDIAN, BIG_ENDIAN, NON_IEEE}; TArch Architecture; }; int
10
by: Sourcerer | last post by:
I wrote this very simple code in .NET VC++. I compiled it on my system, and tried to run it on my friend's computer (he doesn't have the compiler). We both have Windows XP Professional. I have .NET...
13
by: hn.ft.pris | last post by:
Hi: I have the following simple program: #include<iostream> using namespace std; int main(int argc, char* argv){ const double L = 1.234; const int T = static_cast<const int>(L); int arr;
35
by: mwelsh1118 | last post by:
Why doesn't C# allow incremental compilation like Java? Specifically, in Java I can compile single .java files in isolation. The resulting individual .class files can be grouped into .jar files....
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.