How to invoke a delegate object - c#

Hi I'm new to C# and currently working on an app using some 3rd party APIs. I came across two lines of code which appreciate it if you could help. Below is the code similar to the actual sample code I have
bank.Account.NewAcc += delegate (Customer customerInfo) {
Console.WriteLine ("Customer Name : " + customerInfo.Name);
};
The bank.Account.NewAcc is an event while Customer is a class.
Below are the questions:
Can we create a delegate of object and not method?
How can I invoke it? I don't have any other information provided by the APIs
Thank you very much.

Please find below the answers to your questions as per my knowldege:
1. Can we create a delegate of object and not method?
No. You can't. Because delegates mean Function Pointer. They can hold the reference of functions only. And the method's signature must match with the signature of the delegate.
2. How can I invoke it? I don't have any other information provided from the APIs
The delegate which is associated with an event as an event handler can be invoked in two ways. First, when the event will be raised, second, when you invoke event programmatically.

In your sample code, an anonymous delegate with a single parameter of type CustomerInfo has been bound to an event named NewAcc.
Once the NewAcc event is fired, the bound delegates would be executed, the code to fire \ raise the event could be like this:
public Class BankAccount { .....
protected virtual void OnNewAcc(CustomerInfo customerInfo)
{
CustomerEventHandler handler = NewAcc;
if (handler != null)
{
handler(this, customerInfo);
}
}
public event CustomerEventHandler NewAcc;
.... }
I hope this answered your question.

I am not quite sure what you mean by a delegate of "object". I doubt you can though. Delegates represent a list of methods to be called. You can't just assign any object value to it.
You don't invoke (or raise) events. The API does. Judging from the name of NewAcc, I guess the event will be raised when a new account is created. Try doing that to bank.Account. You might see the customer info getting printed. Obviously, this won't work 100%. You have to look inside bank.Account to know exactly when the event will be raised (or just ask the person who wrote it).
Note that the delegate can be written with a lambda expression:
bank.Account.NewAcc += (customerInfo) => Console.WriteLine ("Customer Name : " + customerInfo.Name);

Related

c# event with multiple function overloads

I am trying to make some events the someone can subscribe to, But i want to give the option to use different types of voids that can be used. See the following for clarification:
public event Action<float, float> MouseMove;
public event Action<Vector2> MouseMove;
public event Action MouseMove;
sending of the events
MouseMove(MouseX, MouseY);
MouseMove(new Vector2(MouseX, MouseY));
MouseMove();
So now in threory the user can subscribe in the following ways:
c.MouseMove += DoWithMouseMove;
And now this user has the ability to create the following types of functions depending on his needs like so:
static void DoWithMouseMove(float x, float y)
{
Console.WriteLine(x +" "+ y);
}
or use the following pattern:
static void DoWithMouseMove()
{
Console.WriteLine("Mouse is moving");
}
But this isnt possible because i get the following error:
already contains a definition for 'MouseMove'.
On the class that contains the events
How can i do this or is this not possible?
If something is unclear or needs further clarification let me know, so i can edit the question!
To my knowledge, it is impossible.
Events are little more then a wrapper around a Delegate. They add a public add and remove function, while turning the backing variable Private.
And I do not know of a way to "mix" delegates in the same delegate variable.
Plus even if you could do that, how would you sensibly raise those events? You as the writer of this class are responsible to raise those events and fill all those Parameters. Ideally using a protected RaiseEvent() function.
It is also wierd why you think you need this. In your example, you would propably implement the first option. A event user that does not care for the values (public event Action MouseMove;) would just not retreive those values. And a user that needs a vector (public event Action<Vector2> MouseMove;) could just build one himself from those values.
Edit: I also second that you should follow the established Event pattern: (object sender, customEventArgsInstance e). Do not throw arguments just randomly into the signature, that makes it hard to proces your event.

Is it possible to target an EventHandler in a lambda expression?

For a simple example, if I had some sort of button UI class, could I write a function that takes an expression that points to its Click event handler:
SomeMethod<SomeButtonClass>(button => button.Click);
I'm trying to eliminate some magic strings currently being used for a system to make events awaitable. The code in question is derived from a blog post by Frank Krueger (a worthwhile read, if you want some background).
public static Task<TEventArgs> GetEventAsync<TEventArgs>(this object eventSource, string eventName) where TEventArgs : EventArgs {
//...
Type type = eventSource.GetType();
EventInfo ev = type.GetEvent(eventName);
//...
}
While the specifics inside probably aren't important, the full method allows you to use an Event triggering as the completion source for a Task, making it easier to manage with await. For some class that raises an event, you can tie into a Task based on that event with a simple call.
Task<EventArgs> eventTask = someEventCausingObject.GetEventAsync<EventArgs>("SomeEventHandler");
// traditionally used as someEventCausingObject.SomeEventHandler += ...;
await eventTask;
// Proceed back here when SomeEventHandler event is raised.
I have been using this happily for a couple projects, but it has its drawbacks, one of the biggest being the use of hard-coded event name strings. This makes event name changes turn into runtime exceptions, and determining usage of the event is difficult.
I started trying to make a version that would allow the EventHandler to be passed in as part of an Expression with the goal of something like this:
await someEventCausingObject.GetEventAsync<EventCausingClass, EventArgs>(x => x.SomeEventHandler);
...with the corresponding method signature...
public static Task<TEventArgs> GetEventAsync<TSource, TEventArgs>(this TSource eventSource, Expression<Func<TSource, EventHandler>> eventHandlerExpression) where TEventArgs : EventArgs {
//...
}
Unfortunately, the lambda expression in the calling code causes a compile error:
Error CS0070: The event `SomeEventHandler' can only appear on the left hand side of += or -= when used outside of the type `EventCausingClass'.
This makes some sense given how event handlers are typically used, but I was hoping to find a better solution going forward than the pre-specified string name. It seems searches for combinations of "expression" and "eventhandler" all tend to be polluted with people describing lambda expressions for beginning += event handler assignment. I'm hoping I am missing something obvious here.
No, it is not possible to target an event. Basically event is not a real type member, but just C# syntax which produces add_EventName and remove_EventName methods pair.
You could try refer to these internal methods name, but it's not possible in C# - http://msdn.microsoft.com/en-us/library/z47a7kdw.aspx
There are many similar questions in SO, with the same answer NO - like this one from Jon Skeet https://stackoverflow.com/a/4756021/2170171
If you're real crazy, you can try something like
private static void Subscribe(Action addHandler)
{
var IL = addHandler.Method.GetMethodBody().GetILAsByteArray();
// Magic here, in which we understand ClassName and EventName
???
}
with usage like
Subscribe(() => new Button().Click += null);
You could try using Cecil http://www.mono-project.com/Cecil for analyzing IL, or implement your own logic as it should not be too hard for predictable line of code.
I don't think that it is good solution though, as it just replaces one headache (proper event naming) with another one (proper Subscribe calling). Though, it will help with rename stuff.

Check if a specific event handler method already attached

Related to this question,
Check if an event already exists
but the difference is I just want to know if a particular method is attached to the event. So there may be other methods attached, but I just want to know if a particular one exists.
My environment is C# in dotnet 4.0.
E.g.
Event += MyMethod1;
Event += MyMethod2;
// Some code
if (MyMethod1IsAttachedToEvent())
{
// Achieved goal
}
Is this possible?
No. You cannot.
The event keyword was explicitly invented to prevent you from doing what you want to do. It makes the delegate object for the event inaccessible so nobody can mess with the events handlers.
Source : How to dermine if an event is already subscribed
Late answer here. I believe Parimal Raj answer is correct, as I could not find a way to directly access the events. However, here are two methods I created to get around this:
Delete before adding. If the method isn't there, I did not receive an error trying to delete the nonexistant method. This way you can insure the invocation list calls method1 only once.
Event -= MyMethod1;
Event += MyMethod1;
The objects you are adding an event to may have a .Tag property. You can use the Tag to store info about the methods you already added. Here I only have one method, so I just need to check if Tag is null. But more complicated scenarios can be handled this way:
if(control.Tag == null)
{
//ony added once, when tag is null
control.TextChanged += new EventHandler(validate);
control.Tag = new ControlTag();
}
Event.GetInvocationList().Any(x => x.Method.Name.Equals("yourmethodname"));
foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
{
if ( existingHandler == prospectiveHandler )
{
return true;
}
}
loop through the delegates using the GetInvocationList method.

Dictionary of events

Is there anything in c# that you can use to create a collection of events like lists, hashsets, and a dictionary in this case? Thankyou.
Sure you can:
Dictionary<String, Delegate> m_events = new Dictionary<String, Delegate>();
In Jeff Richter's Book CLR via C# you can find a complete implementation of an EventSet class.
(Even if you don't have the book you can download the sample code from https://www.wintellect.com/wp-content/uploads/2017/09/CLR-via-C-4th-Edition-Code.zip. The class in question is in "Ch11-1-EventSet.cs".)
As far as the question goes what an event is:
Say you have this line of code in your class:
public event EventHandler<NewMailEventArgs> NewMail;
then the C# compiler will translate the line above into three constructs:
A private delegate field. (Something like: private EventHandler<NewMailEventArgs> NewMail;
A public add_Xxx method (where Xxx is the Event name) that interested subscribers can use to register a callback delegate with the event.
A public remove_Xxx method (where Xxx is the Event name) that subscribers can use to unregister from the event.
(All the gory details can be found in section 11.2 of aforementioned book.)
So in other words the 'thing' you can store in your Event collection class is just a plain old delegate nothing else.
An event is like a property or method; you cant store instances of them. You can use reflection, but this likely isn't what you want.
Did you mean you want to store a list of methods to call when your event is fired? Events already do that.
EDIT:
Ah, I think I get it now. If you just simply fire your event, only the B instances that want it will get it. If you pass into the event args the instance of A that fired the event, then the B instance will be able to tell where it came from. But a B will never get an event from an A that it didn't ask for an event.
EDIT:
Maybe not. You only want to fire an event on one of the B's? Make B implement an interface that has a callback method. Instead of firing an event, call the method on the correct instance of B.
You could use IList with out any trouble. Type T could be any type defined in .net or user defined class.

Why can I check some event handlers for null, some not?

I have a ugly piece of code that adds event handlers. The problem is, if the code is called multiple times, the event handlers are called multiple times.
To solve the problem, I remove the event handler first and then add it.
Now I've seen the following behaviour:
Some event handlers can be checked like:
if (object.event == null) {
//
// Code
//
}
others of the form
if (object.object.event == null) {
//
// Code
//
}
I get a message like 'object.object.event' may only occur left of -= or +=.
(Since I'm using a german version of visual studio, I don't know the correct translation to english).
I have no idea why the behaviour looks this inconsequent so I would be grateful for some information on this.
To be more specific: It's user control.
if (myControl.Event == null) {
//
// works
//
}
if (myControl.TreeView.NodeMouseClick == null) {
//
// doesn't work
//
}
To solve the problem, I remove the event handler first and then add it.
That doesn't solve the problem. The event keyword provides accessors for a delegate object. Much like a property provides accessors for a field. On a property, you always need one get or set. An event has the add, remove and raise accessors. But the compiler will generate a default implementation for them if you don't do so yourself. Which is fairly common.
The advantage of a property accessor is that the backing field can be private. Nobody can mess with it, except the class that contains the field. All access has to go through the get and set accessors. The event keyword works exactly the same way, nobody can mess with the delegate object, except the code in the class that contains the event.
Which shoots a gaping hole in your attempt to avoid raising the event. You cannot mess with the list of subscribers for an event that's declared in another class, the compiler is telling you this. The normal way this is done is setting a bool flag to indicate that events have to be temporarily ignored. The event handler can check that flag and avoid executing any side-effects.
SLaks is correct, and has linked to some excellent resources. Here's a relevant quote from Chris Burrows' blog article:
Let me take a quick detour here and explain to you how the binding of += works in C#. There are two possibilities:
either there is an actual + operator, such as with ints, and x += y binds to “x = x + y” except that x is only evaluated once. This is the compound assignment operator; or
the thing on the left hand side is an event, and x.E += y binds to “x.add_E(y)”. This is the event accessor operator, and in fact this is the only way to bind to an event accessor.
So what do we have in the snippet above? Well, the extra bit of detail that you need to decide is the following rule about field-like events in C#: outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.
In your case, when resolving myControl.Event, you're inside the myControl class, so you don't see an event object; instead you see an actual delegate object, which you can compare with null. When resolving myControl.TreeView.NodeMouseClick, you're outside the TreeView class, so you can't access the actual delegate object; all you get is the event object, which cannot be compared to null.
If I understand correctly, all of this wouldn't help you anyway, since presumably after you check for null, you're going to try to fire the TreeView's event for it, which you can't do.
Depending on what you're trying to do, you could probably subclass TreeView and add an internal method that would call the protected TreeView.OnNodeMouseClick method to fire the event.
You can only access the backing field for an event defined in your class.
For more information, see the spec. (Although this has changed in C# 4, the changes are irrelevant to you)
Best practice in your case would be to create a protected internal OnEventName method in each class.
You can only query your own eventhandlers for attached listeners.
Automatic events, like this one:
public event EventHandler SomethingHappened;
are implemented by the compiler using a multicast delegate.
When you write myControl.Event == null, the compiler actually needs to call Delegate.GetInvocationList on that delegate. The compiler does not let you do that unless the code is inside a method of the class exposing the event, hence the error (it only allows you to add or remove from the invocation list).
If we were talking about an event you define in your own class, then you would have the option of exposing the invocation list (e.g. through a method) and doing what you are trying to do. But for existing classes (e.g. TreeView) it is not possible.

Categories