One of the niceties included with C# 3.0 is lambda expressions, a concise syntax for implementing anonymous methods. Lambda expressions can be over-used, but they're very handy for certain kinds of things, like defining how asynchronous callbacks should be handled, all within a single method.
Lambda expressions are also very handy for implementing event handlers. For instance, if you've got an AlarmClock class that looks like this:
class
AlarmClock
You would normally assign and implement an event-handler like this, with a separate defined method:
class
Program
But with lambda expressions, you can do it like this, all in one method:
class
Program
Most folks would agree that this looks cleaner, and is easier to follow. (At least, once you get the hang of lambda expressions, which admittedly have a rather odd syntax.)
The one time this doesn't work is when you need to be able to clear event handlers as well as assign them. The way that you normally do this is so:
public
static
void Main()
But you can't do that with the lambda expression I used above, because you don't have any way to identify the lambda expression that you want to remove. I've seen a variety of folks asking questions about how to clear event handlers implemented as lambda expressions for this very reason.
It turns out that there are (at least) two ways to do it.
class
AlarmClock
public
static
void Main() The syntax for #2 is a bit unwieldy, but it can let you do things that would be difficult or complicated if you had to use a second method. For instance, within lambda expressions you can use local variables declared at the level of the containing function:
public
static
void Main()
To duplicate this without lambda expressions, you'd have to declare the resetEvent and alarmSounded variables at the class level, which isn't nearly as clean, and could lead to some odd bugs if other methods were trying to use those same variables simultaneously.
{
public
event
EventHandler<EventArgs> Alarm;
public
void SoundAlarm()
{
if (Alarm != null)
{
Alarm(this, new
EventArgs());
}
}
}
{
public
static
void Main()
{
AlarmClock clock = new
AlarmClock();
clock.Alarm += new
EventHandler<EventArgs>(clock_Alarm);
clock.SoundAlarm();
}
static
void clock_Alarm(object sender, EventArgs e)
{
Console.WriteLine("The alarm went off at {0}.", DateTime.Now);
}
}
{
public
static
void Main()
{
AlarmClock clock = new
AlarmClock();
clock.Alarm += (s, e) =>
Console.WriteLine("The alarm went off at {0}.", DateTime.Now);
clock.SoundAlarm();
}
}
{
AlarmClock clock = new
AlarmClock();
clock.Alarm += new
EventHandler<EventArgs>(clock_Alarm);
clock.SoundAlarm();
clock.Alarm -= new
EventHandler<EventArgs>(clock_Alarm);
}
{
public
event
EventHandler<EventArgs> Alarm;
public
void SoundAlarm()
{
if (Alarm != null)
{
Alarm(this, new
EventArgs());
}
}
public
void ClearEventHandlers()
{
Alarm = null;
}
}
{
AlarmClock clock = new
AlarmClock();
EventHandler<EventArgs> handleAlarm = null;
handleAlarm = (s, e) =>
{
clock.Alarm -= handleAlarm;
Console.WriteLine("The alarm went off at {0}.", DateTime.Now);
};
clock.Alarm += handleAlarm;
clock.SoundAlarm();
}
Note that you need to assign the handleAlarm variable to null first, because otherwise the compiler complains about the first line of the lambda expression: it thinks that you're trying to muck about with an uninitialized variable. This is only sort of true, but to work around it, just assign the variable to null when you declare it.
{
AlarmClock clock = new
AlarmClock();
EventHandler<EventArgs> handleAlarm = null;
ManualResetEvent resetEvent = new
ManualResetEvent(false);
bool alarmSounded = false;
handleAlarm = (s, e) =>
{
clock.Alarm -= handleAlarm;
Console.WriteLine("The alarm went off at {0}.", DateTime.Now);
alarmSounded = true;
resetEvent.Set();
};
clock.Alarm += handleAlarm;
clock.SoundAlarm();
resetEvent.WaitOne(5000);
if (!alarmSounded)
{
Console.WriteLine("The alarm didn't sound within the timeout period.");
}
}
Monday, August 10, 2009
Clearing event handlers implemented with lambda expressions
Posted by
Ken Smith
at
8:05 PM
|
Links to this post
Windows 7: Not Terribly Impressed
Windows Vista was never as bad as its reputation; and Windows 7 is not as good as everyone claims. It's not bad, but it still needs some work. And I dislike some of the design decisions.
Here are a few snippets from my own experience:
The computer has rebooted from a bugcheck. The bugcheck was: 0x0000001a (0x00001236, 0x878be008, 0x878be08c, 0x00070054). A dump was saved in: C:\Windows\MEMORY.DMP. Report Id: 081009-37970-01. The computer has rebooted from a bugcheck. The bugcheck was: 0x0000008e (0xc0000005, 0x8c28b885, 0xb062b750, 0x00000000). A dump was saved in: C:\Windows\MEMORY.DMP. Report Id: 081009-30061-01.
Again, none of these things are killers, and maybe some people will like the new UI and its associated defaults. On the whole, Windows 7 is OK, though not terribly impressive. It feels to me like a not-very-ambitious bug-fix to Vista. I'll run it. But I continue to wish that MS could be more successful at their core operating system business.
It's also much more difficult and confusing to tell at a glance if something is open. I don't get why MS thought that clicking twice is better than clicking once. Luckily, you can turn this behavior off; but it's still an odd default.
Posted by
Ken Smith
at
9:49 AM
|
Links to this post
