Can anybody please tell me what is happening in below code in simple English, specifically around the usage of => and += symbols:
var ls = new LibraryServiceClient(AppSettings.Get("LibraryServiceBaseAddress"),
SessionId, App.Id, _user.UUID);
ls.MakingRequest += (s, e) =>
{
LogStash.LogDebug("Library Service | Before making request : {0}",
DateTime.UtcNow.ToString("HH:mm:ss.fff"));
};
You assign a new delegate to the event:
ls.MakingRequest +=
You create a lambda expression, a function having two parameters, s and e:
(s, e) =>
Where the action of the lambda expression is:
{ LogStash.LogDebug("Library Service | Before making request : {0}", DateTime.UtcNow.ToString("HH:mm:ss.fff"));
(s,e) => { /*expresion*/ }
is a lambda function.
It's type is Action<object, EventArgs>.
ls.MakingRequest
is an event.
With += you register a handler to this event.
When the event is fired all registered handlers will execute.
A handler has the same signature as the action - it takes an object sender and an EventArgs eventArgs and returns void.
Thus, the lambda function type is compatible, so it will be called when the event is fired.
It is a syntactical sugar to make chained extension methods look more readable.
Below code will explain its evolution:
public class Program
{
public void Main(string[] args)
{
// named delegate
Tasker t = new Tasker();
t.doer += DoProvider.DoThis;
t.CallDoer("I am doing something");
// anonymous method
Tasker t2 = new Tasker();
t2.doer += delegate(string s){
Console.WriteLine (s);
};
t2.CallDoer("I am doing something again");
// syntactical sugar over anonymous methods aka lambda expressions
Tasker t3 = new Tasker();
t3.doer += (s)=>{
Console.WriteLine (s);
};
t3.CallDoer("I am doing yet another thing");
}
}
public delegate void DoSomething(string Foo);
public class Tasker
{
public event DoSomething doer;
public void CallDoer(string s)
{
doer.Invoke(s);
}
}
public static class DoProvider
{
public static void DoThis(string Bar)
{
Console.WriteLine (Bar);
}
}
Related
Doing a Pluralsight video and can't find out why it's wrong.
Error Message on this point:
worker.WorkPerformed += new EventHandler<WorkPerformedEventArgs>(worker_WorkPerformed);
Error Message:
Cannot implicity convert to type
'System.EventHandler<AB_Events.WorkPerformedEventArgs>' to
'AB_Events.WorkPerformedHandler'
Snippets
public delegate int WorkPerformedHandler(object sender,WorkPerformedEventArgs e);
public class Worker
{
public event WorkPerformedHandler WorkPerformed;
protected virtual void OnWorkPerformed(int hours, WorkType workType)
{
var del = WorkPerformed as WorkPerformedHandler;
if (del != null)
{
del(this, new WorkPerformedEventArgs(hours, workType));
}
}
}
And
class Program
{
static void Main(string[] args)
{
var worker = new Worker();
worker.WorkPerformed += new EventHandler<WorkPerformedEventArgs>(worker_WorkPerformed);
Console.ReadKey();
}
public static void worker_WorkPerformed(object sender, WorkPerformedEventArgs e)
{
throw new NotImplementedException();
}
}
Although methods and anonymous functions are implicitly convertible to a delegate type that matches their signature, a delegate instance is not implicitly convertible to another delegate type.
You need to use either EventHandler<TEventArgs> or your WorkPerformedHandler, but not both:
public class Worker
{
public event WorkPerformedHandler WorkPerformed;
//...
}
Or:
public class Worker
{
public event EventHandler<WorkPerformedEventArgs> WorkPerformed;
//...
}
Also, because worker_WorkPerformed can be implicitly converted to either type, the most concise syntax would be this:
worker.WorkPerformed += worker_WorkPerformed; // Implicit conversion
If you do go with your WorkPerformedHandler delegate, make sure you change the return type to void as per the signature of worker_WorkPerformed:
public delegate void WorkPerformedHandler(object sender, WorkPerformedEventArgs e);
It is generally not advisable to return from an event handler anyway, as there can be multiple subscribers.
what i have done is to replace WorkPerformedHandler by EventHandler<WorkPerformedEventArgs>
public delegate int WorkPerformedHandler(object sender, WorkPerformedEventArgs e);
public class Worker
{
public event EventHandler<WorkPerformedEventArgs> WorkPerformed;
protected virtual void OnWorkPerformed(WorkPerformedEventArgs e)
{
WorkPerformed?.Invoke(this, e);
}
}
event subscription :
var worker = new Worker();
worker.WorkPerformed += new EventHandler<WorkPerformedEventArgs>(worker_WorkPerformed);
I know there are times you need to keep track of a delegate so that it can be unsubscribed properly:
private EventHandler _handler;
public void Foo()
{
if (_handler != null)
{
Something.SomeEvent -= _handler; // Unsubscribe old event
}
_handler = delegate(object sender, EventArgs args) { };;
Something.SomeEvent += _handler;
}
But, is that still necessary if you use a method instead?
public void CustomMethod(object sender, EventArgs args) { ... }
public void Foo()
{
// Not sure how to unsubscribe only if it wasn't subscribed first?
if (some way to check)
{
Something.SomeEvent -= CustomMethod;
}
Something.SomeEvent += CustomMethod;
}
No, it's not necessary. If you are always subscribing/unsubscribing the same method (in the form of a delegate), then you don't need to track the actual delegate instance that was subscribed. The new delegate instances (implicitly created for you by the C# compiler in the += and -= operations) are correctly identified as identical, so that the -= operation removes the delegate that was added in the += operation.
In other words, equality for the Delegate class is not just "reference equality". Two completely different Delegate instances that have the same invocation list are considered equal.
If you wanna check if a specific method subscribed or not you can use GetInvocationList and then Linq:
var mInfo = typeof(SomeType).GetMethod("CustomMethod");
if(Something.SomeEvent.GetInvocationList().Any(x => x.Method == mInfo))
{
}
Reading event description and examples of msdn I can see a discrepancy in the way events are subscribed to. Sometimes event handlers are passed "as is" and other times they are passed by instantiating a delegate using the handler method e.g.
...
class Subscriber
{
private string id;
public Subscriber(string ID, Publisher pub)
{
id = ID;
// Subscribe to the event using C# 2.0 syntax
pub.RaiseCustomEvent += HandleCustomEvent;
}
// Define what actions to take when the event is raised.
void HandleCustomEvent(object sender, CustomEventArgs e)
{
Console.WriteLine(id + " received this message: {0}", e.Message);
}
}
vs
public delegate void EventHandler1(int i);
...
public class TestClass
{
public static void Delegate1Method(int i)
{
System.Console.WriteLine(i);
}
public static void Delegate2Method(string s)
{
System.Console.WriteLine(s);
}
static void Main()
{
PropertyEventsSample p = new PropertyEventsSample();
p.Event1 += new EventHandler1(TestClass.Delegate1Method);
p.RaiseEvent1(2);
...
}
}
Can someone please provide clarity on this?
Thanks.
Your first code sample is syntactic sugar for the second one.
This syntax (omitting the constructor) was introduced by C# 2.
I know this is slightly a duplicate of this question here: Blocking and waiting for an event
However, I was in the process of writing a EventWaiter and ran into a problem. Here is a (majorly) simplified version of what I've been working on:
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent()
{
MethodInfo method = this.GetType().GetMethod("DynamicCaller");
Delegate handler = Delegate.CreateDelegate(this._event.EventHandlerType, this, method);
_event.AddEventHandler(_eventContainer, handler);
_autoResetEvent.WaitOne();
_event.RemoveEventHandler(_eventContainer, _handler);
}
public void DynamicCaller(/* insert magic here */)
{
_autoResetEvent.Set();
}
}
The usage would simply be:
EventWaiter ew = new EventWaiter(someClass, "someEvent");
ew.WaitForEvent();
Basically what is happening, is its registering the DynamicCaller void as a handler for this event. The problem is, events have different signatures, and I want to be able to handle the event regardless of the delegate used.
I can get the type of the delegate with this._event.EventHandlerType but how can I use to that create a completely reusable class no matter what the delegate is? If the DynamicCaller parameters are not exactly the same as the event delegate parameters i get an exception.
As a side note, I did a bunch of looking into code in the framework, and if i had access to some of that I think this would be easy. Too bad that alot of the classes I would need are all internal to the framework.
Since all events that respect the recommended pattern have a parameter of type object and a parameter of a type that derives from EventArgs, you should be able to handle all these events with this signature:
void DynamicCaller(object sender, EventArgs e)
Of course it won't work for non-standard event signatures...
EDIT: here's an example with a dynamically generated handler:
public class EventWaiter
{
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventInfo _event = null;
private object _eventContainer = null;
public EventWaiter(object eventContainer, string eventName)
{
_eventContainer = eventContainer;
_event = eventContainer.GetType().GetEvent(eventName);
}
public void WaitForEvent()
{
Delegate handler = CreateHandler();
_event.AddEventHandler(_eventContainer, handler);
_autoResetEvent.WaitOne();
_event.RemoveEventHandler(_eventContainer, handler);
}
private Delegate CreateHandler()
{
var invokeMethod = _event.EventHandlerType.GetMethod("Invoke");
var invokeParameters = invokeMethod.GetParameters();
var handlerParameters = invokeParameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
var body = Expression.Call(Expression.Constant(_autoResetEvent), "Set", null);
var handlerExpression = Expression.Lambda(_event.EventHandlerType, body, handlerParameters);
return handlerExpression.Compile();
}
}
EDIT: SLaks was faster than me ;)
You should use expression trees to compile a method with an arbitrary set of parameters that calls your callback:
Expression.Lambda(
_event.EventHandlerType,
Expression.Call(Exrpession.Constant(_autoResetEvent),
typeof(AutoResetEvent).GetMethod("Set")),
_event.EventHandlerType.GetMethod("Invoke")
.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType))
).Compile();
Note that you can make your system type-safe using generics and expression trees:
new EventWaiter(_ => someObject.SomeEvent += _)
Where _ is an ordinary (but short) parameter name.
You could do what you want with TaskCompletionSource:
TaskCompletionSource<string> tcs =
new TaskCompletionSource<string>();
WebClient client = new WebClient();
client.DownloadStringCompleted += (sender, args) => {
if (args.Error != null) tcs.SetException(args.Error);
else if (args.Cancelled) tcs.SetCanceled();
else tcs.SetResult(args.Result);
};
client.DownloadStringAsync(address);
tcs.Task.Wait(); // WaitForEvent
The solutions here are good, but for me, using strings, reflection has a bit of a code smell, so I'll go for a generic version:
public class EventWaiter
{
public enum Mode
{
Wait,
Detach
}
public static Func<Mode, TEventArgs> Create<TDelegate, TEventArgs>(
Func<Action<object, TEventArgs>, TDelegate> converter,
Action<TDelegate> addHandler,
Action<TDelegate> removeHandler
)
{
AutoResetEvent semaphore = new AutoResetEvent(false);
TEventArgs args = default(TEventArgs);
TDelegate handler = converter((s, e) => { args = e; semaphore.Set(); });
addHandler(handler);
return mode =>
{
if (mode == Mode.Wait)
{
semaphore.WaitOne();
return args;
}
else
{
removeHandler(handler);
return default(TEventArgs);
}
};
}
Usage:
var evt =
EventWaiter.Create<SerialDataReceivedEventHandler, SerialDataReceivedEventArgs>
(handler => (s, e) => handler(s, e),
h => port.DataReceived += h,
h => port.DataReceived -= h);
var firstArgument = evt(EventWaiter.Mode.Wait); //Wait for first event
var secondArgument = evt(EventWaiter.Mode.Wait); //Wait for second event
evt(EventWaiter.Mode.Detach); //Dispose
Is it possible to unsubscribe an anonymous method from an event?
If I subscribe to an event like this:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
I can un-subscribe like this:
MyEvent -= MyMethod;
But if I subscribe using an anonymous method:
MyEvent += delegate(){Console.WriteLine("I did it!");};
is it possible to unsubscribe this anonymous method? If so, how?
Action myDelegate = delegate(){Console.WriteLine("I did it!");};
MyEvent += myDelegate;
// .... later
MyEvent -= myDelegate;
Just keep a reference to the delegate around.
One technique is to declare a variable to hold the anonymous method which would then be available inside the anonymous method itself. This worked for me because the desired behavior was to unsubscribe after the event was handled.
Example:
MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Since C# 7.0 local functions feature has been released, the approach suggested by J c becomes really neat.
void foo(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
So, honestly, you do not have an anonymous function as a variable here. But I suppose the motivation to use it in your case can be applied to local functions.
From memory, the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods.
If you need to unsubscribe, you should either use a "normal" method or retain the delegate somewhere else so you can unsubscribe with exactly the same delegate you used to subscribe.
In 3.0 can be shortened to:
MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
Instead of keeping a reference to any delegate you can instrument your class in order to give the event's invocation list back to the caller. Basically you can write something like this (assuming that MyEvent is declared inside MyClass):
public class MyClass
{
public event EventHandler MyEvent;
public IEnumerable<EventHandler> GetMyEventHandlers()
{
return from d in MyEvent.GetInvocationList()
select (EventHandler)d;
}
}
So you can access the whole invocation list from outside MyClass and unsubscribe any handler you want. For instance:
myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
I've written a full post about this tecnique here.
Kind of lame approach:
public class SomeClass
{
private readonly IList<Action> _eventList = new List<Action>();
...
public event Action OnDoSomething
{
add {
_eventList.Add(value);
}
remove {
_eventList.Remove(value);
}
}
}
Override the event add/remove methods.
Keep a list of those event handlers.
When needed, clear them all and re-add the others.
This may not work or be the most efficient method, but should get the job done.
If you want to be able to control unsubscription then you need to go the route indicated in your accepted answer. However, if you are just concerned about clearing up references when your subscribing class goes out of scope, then there is another (slightly convoluted) solution which involves using weak references. I've just posted a question and answer on this topic.
One simple solution:
just pass the eventhandle variable as parameter to itself.
Event if you have the case that you cannot access the original created variable because of multithreading, you can use this:
MyEventHandler foo = null;
foo = (s, ev, mehi) => MyMethod(s, ev, foo);
MyEvent += foo;
void MyMethod(object s, MyEventArgs ev, MyEventHandler myEventHandlerInstance)
{
MyEvent -= myEventHandlerInstance;
Console.WriteLine("I did it!");
}
If the best way is to keep a reference on the subscribed eventHandler, this can be achieved using a Dictionary.
In this example, I have to use a anonymous method to include the mergeColumn parameter for a set of DataGridViews.
Using the MergeColumn method with the enable parameter set to true enables the event while using it with false disables it.
static Dictionary<DataGridView, PaintEventHandler> subscriptions = new Dictionary<DataGridView, PaintEventHandler>();
public static void MergeColumns(this DataGridView dg, bool enable, params ColumnGroup[] mergedColumns) {
if(enable) {
subscriptions[dg] = (s, e) => Dg_Paint(s, e, mergedColumns);
dg.Paint += subscriptions[dg];
}
else {
if(subscriptions.ContainsKey(dg)) {
dg.Paint -= subscriptions[dg];
subscriptions.Remove(dg);
}
}
}
if you want refer to some object with this delegate, may be you can use Delegate.CreateDelegate(Type, Object target, MethodInfo methodInfo)
.net consider the delegate equals by target and methodInfo
There is a way to solve this by implementing the closure yourself instead of a lambda expression.
Assume that the class to be used as a capture variable is as follows.
public class A
{
public void DoSomething()
{
...
}
}
public class B
{
public void DoSomething()
{
...
}
}
public class C
{
public void DoSomething()
{
...
}
}
These classes will be used as capture variables, so we instantiate them.
A a = new A();
B b = new B();
C c = new C();
Implement the closure class as shown below.
private class EventHandlerClosure
{
public A a;
public B b;
public C c;
public event EventHandler Finished;
public void MyMethod(object, MyEventArgs args)
{
a.DoSomething();
b.DoSomething();
c.DoSomething();
Console.WriteLine("I did it!");
Finished?.Invoke(this, EventArgs.Empty);
}
}
Instantiate the closure class, create a handler, then subscribe to the event and subscribe to the lambda expression that unsubscribes from the closure class's Finished event.
var closure = new EventHandlerClosure
{
a = a,
b = b,
c = c
};
var handler = new MyEventHandler(closure.MyMethod);
MyEvent += handler;
closure.Finished += (s, e)
{
MyEvent -= handler;
}
I discovered this quite old thread recently for a C# project and found all the answers very useful. However, there was one aspect that didn't work well for my particular use case - they all put the burden of unsubscribing from an event on the subscriber. I understand that one could make the argument that it's the subscribers job to handle this, however that isn't realistic for my project.
My primary use case for events is for listening to timers to sequence animations (it's a game). In this scenario, I use a lot of anonymous delegates to chain together sequences. Storing a reference to these isn't very practical.
In order to solve this, I've created a wrapper class around an event that lets you subscribe for a single invocation.
internal class EventWrapper<TEventArgs> {
private event EventHandler<TEventArgs> Event;
private readonly HashSet<EventHandler<TEventArgs>> _subscribeOnces;
internal EventWrapper() {
_subscribeOnces = new HashSet<EventHandler<TEventArgs>>();
}
internal void Subscribe(EventHandler<TEventArgs> eventHandler) {
Event += eventHandler;
}
internal void SubscribeOnce(EventHandler<TEventArgs> eventHandler) {
_subscribeOnces.Add(eventHandler);
Event += eventHandler;
}
internal void Unsubscribe(EventHandler<TEventArgs> eventHandler) {
Event -= eventHandler;
}
internal void UnsubscribeAll() {
foreach (EventHandler<TEventArgs> eventHandler in Event?.GetInvocationList()) {
Event -= eventHandler;
}
}
internal void Invoke(Object sender, TEventArgs e) {
Event?.Invoke(sender, e);
if(_subscribeOnces.Count > 0) {
foreach (EventHandler<TEventArgs> eventHandler in _subscribeOnces) {
Event -= eventHandler;
}
_subscribeOnces.Clear();
}
}
internal void Remove() {
UnsubscribeAll();
_subscribeOnces.Clear();
}
}
The side benefit of having this in a class is that you can make it private and expose only the functionality you want. For example, only expose the SubscribeOnce (and not the Subscribe) method.
public class MyClass {
private EventWrapper<MyEventEventArgs> myEvent = new EventWrapper<MyEventEventArgs>();
public void FireMyEvent() {
myEvent.Invoke(this, new MyEventEventArgs(1000, DateTime.Now));
}
public void SubscribeOnce(EventHandler<MyEventEventArgs> eventHandler) {
myEvent.SubscribeOnce(eventHandler);
}
public class MyEventEventArgs : EventArgs {
public int MyInt;
public DateTime MyDateTime;
public MyEventEventArgs(int myInt, DateTime myDateTime) {
MyInt = myInt;
MyDateTime = myDateTime;
}
}
}
The tradeoff here is more overhead for having an instance of this for each event, however in my scenario - this is an acceptable tradeoff to ensure that garbage gets collected efficiently and the code is more maintainable on the subscriber side. Full example here.
Here is a simple solution, which removes all assigned methods from an event. Also anonymous methods.
Use this code and adjust the names.
if (MyEvent != null)
foreach (Delegate del in MyEvent.GetInvocationList())
MyEvent -= (EventHandler<MyEventHandlerType>)del;
Example usage
public class SomeClass
{
public event EventHandler<NiceEventArgs> NiceEvent;
public void RemoveHandlers()
{
if (NiceEvent != null)
foreach (Delegate del in NiceEvent.GetInvocationList())
NiceEvent -= (EventHandler<NiceEventArgs>)del;
}
}
Thanks to hemme's answer, which I used as inspiration.