I was wiring up an event to use a lambda which needed to remove itself after triggering. I couldn't do it by inlining the lambda to the += event (no accessable variable to use to remove the event) so i set up an Action<object, EventArgs>
variable and moved the lambda there. The main error was that it could not convert an Action<object, EventArgs>
to an EventHandler. I thought lambda expressions were implicitly convertable to event handlers, why doesn't this work?
views:
155answers:
4
+1
A:
You can use an anonymous method instead:
Event += (sender, e) =>
{
// Multiple lines
// of code here
};
nasufara
2009-10-11 22:27:58
That's the whole point.... I have one set up only stored into a variable to i can have the event remove itself when fired, only it won't work.
RCIX
2009-10-11 22:29:55
declare the variable as an EventHandler and you should be OK...
Thomas Levesque
2009-10-11 22:37:42
+5
A:
Lambdas are implicitly convertible to delegate types with the right shape, but two same-shaped delegate types are not implicitly convertible to one another. Just make the local variable have type EventHandler instead.
EventHandler h = (o, ea) => { ... };
e += h;
...
e -= h;
(in case it helps:
Action<object, EventArgs> a = (o, ea) => { };
EventHandler e = a; // not allowed
EventHandler e2 = (o,ea) => a(o,ea); // ok
)
Brian
2009-10-11 22:30:10
Except that e2 now goes through two function calls to actually do anything... eww.
Matthew Scharley
2009-10-11 22:47:28
I'm not promoting e2 as a good way to write code, I'm just using it as an example to demonstrate what is and is not legal with regards to the C# type system.
Brian
2009-10-11 23:06:12
It strikes me as a bit silly that you can't cast from one delegate type to another that is equivalent. Is there any good reason for this?
Snarfblam
2009-10-12 00:58:36
@Snarfblam: I'm guessing it's the covariance issue, as delegates are generics. I wonder if this issue has gone in .NET 4.
Cameron MacFarland
2009-10-12 09:40:08
@Cameron - it has not. The new 4.0 covariance translates between `Func<string>` and `Func<object>` where appropriate, but that is because they are both kinds of `Func<T>` delegate. If they used a different named delegate type, they would be incompatible. The simple solution is to always use `Func` or `Action` to represent delegates. They allow up to 8 parameters in 4.0. The only limitation of them is that they don't allow the parameters to be `out` or `ref`, which is possible with custom named delegate types.
Daniel Earwicker
2009-10-14 09:36:19
On whether there is much value in using custom delegate types for events, see http://stackoverflow.com/questions/1120506/what-would-i-lose-by-abandoning-the-standard-eventhandler-pattern-in-net
Daniel Earwicker
2009-10-14 09:39:04
+2
A:
In general, delegates can't be cast because they have no inheritance tree defining which casts are valid. To that end, you have two choices:
- Use a variable of type
EventHandler
instead of theAction<T1, T2>
Use an inline declaration.
// option 1: local variable EventHandler eh = (o, ea) => { /* [snip] */ }; obj.event += eh; obj.event -= eh; // option 2: inline declaration obj.event += (o, ea) => { /* [snip] */ };
Matthew Scharley
2009-10-11 22:34:20
The whole point of using a variable was so that i could remove the event from the event handler while still inside the event. Still, +1.
RCIX
2009-10-11 22:36:21
+1
A:
Action<Object, EventArgs> a = (o, ea) => { };
EventHandler e = a.Invoke;
QrystaL
2009-10-12 09:35:02