Sending My Own Arguments To A Event Handler? - c#

I'm working with AssemblyResolve specifically. Here is my code first, then my question follows:
var a = AppDomain.CurrentDomain;
a.AssemblyResolve += new ResolveEventHandler(HandleIt);
Private Assembly HandleIt(object sender, ResolveEventArgs args){
//Does stuff, returns an assembly
}
So I add HandleIt to my AssemblyResolve event. How can I add it to that event and pass an argument with it like:
a.AssemblyResolve += new ResolveEventHandler(HandleIt(AnArgument));
This is throwing me off since HandleIt takes arguments, but none are explicetly passed when it is added to the AssemblyResolve event. I would expect something like:
a.AssemblyResolve += new ResolveEventHandler(HandleIt(aSender,someArgs));
So yeah, I just want to be able to send another argument to my HandleIt function when adding it to my AssemblyResolve event.
Hope that makes sense, thanks.
Addendum:
if(aBool){
a.AssemblyResolve += new ResolveEventHandler(HandleA);
}
else{
a.AssemblyResolve += new ResolveEventHandler(HandleB);
}
HandleA(object sender, ResolveEventArgs args){
Handle(true);
}
HandleB(object sender, ResolveEventArgs args){
Handle(false);
}
Handle(bool isA){
}
-vs-
if(aBool){
a.AssemblyResolve += (object s, ResolveEventArgs a) => Handle(s,a,true);
}
else{
a.AssemblyResolve += (object s, ResolveEventArgs a) => Handle(s,a,false);
}
Handle(object sender, ResolveEventArgs args, bool isA){
}

When the event is fired arguments are passed to the method if you would like to bind additional arguments you could do that with a lambdaexpression
var a = AppDomain.CurrentDomain;
a.AssemblyResolve += (object s,ResolveEventArgs a) => HandleIt(s,a,someArgument);
Private Assembly HandleIt(object sender, ResolveEventArgs args, SomeType arg){
//Does stuff, returns an assembly
}
where someArgument is the value you wish to bind.
This is essentially using lambdas to do a partial application of a function. Something that C# doesn't support directly but is very common in other languages. Partial application is very closely related to Currying that exists in languages such as F# and Haskell of course (since the concept gets it's name from Haskell Curry) and various other functional langauages. They differ in the result type.
They are both related to closures (as the concept in the above code is called) and in languages that don't support partial application or currying you can use closures to accomplish something similar. However be aware that closures differ from partial application in ways that can create some surprising bugs. E.g.
int i = 1;
Func<int> f = () => i;
i = 2;
System.Console.WriteLine(f());
prints 2 to the console. Because closures captures a reference to a variable not the value of said variable. This is a common error in for loops, when closing over the loop variable(s) of the for loop.

AppDomain.CurrentDomain will raise the event and pass parameters, the += line is simply registering a handler to the event, parameters there would not make any sense.
Analogy:
You register your address with the postman, and he deilivers mail to that address later. When you register at the post office, you do not hand them the mail you want delivered to you later!

It's not possible.
HandleIt in this case is a delegate to and has to match the signature of ResolveEventHandler
a.AssemblyResolve += new ResolveEventHandler(HandleIt);
Setting it in this line just tells the code what to execute when AssemblyResolve is raised the thing that raises the AssemblyResolved event will pass it's parameters. You could re-raise another event with your own parameters and hook that to another handler (or just call a method).
EDIT: Or maybe you can with Lamda's :o

A bit more technical: You are registering a delegate to your method with the event. This is something else than a call to the method.
It is a bit similar to this:
Action<object, ResolveEventArgs> handleItDelegate = HandleIt;
When the event is fired, the delegate is invoked. The analogy of my sample would be:
handleItDelegate(sender, eventArgs);
UPDATE:
In a comment, you clarified, what you want to achieve: You want to trigger the event, so your assembly is loaded. You can't do that, the way you think it works. To load your assembly manually, just do so, no need for the event. The event is called, when the runtime tries to resolve a referenced assembly, but can't find it.

Related

AssemblyResolve not fired with anonymous handler

I'm trying to resolve dynamically loaded assemblies, but the AssemblyResolve event does not appear to work with anonymous functions.
private void Load() {
ResolveEventHandler resolve = (sender, args) => Assembly.LoadFile(pathToDependency);
AppDomain.CurrentDomain.AssemblyResolve += resolve;
AppDomain.CurrentDomain.AssemblyResolve += this._AssemblyResolve;
Assembly.LoadFile(pathToDll);
}
private void _AssemblyResolve(Object sender, ResolveEventArgs args) {
return Assembly.LoadFile(pathToDependency);
}
this._AssemblyResolve and resolve are virtually the same function, except that the anonymous resolve function creates a closure that uses a variable defined in the Load method.
For some reason, this._AssemblyResolve gets called, but resolve doesn't. Why?
I can't really rely on the _AssemblyResolve method because the method needs to know about a variable that is defined in the Load method. I can use a workaround, but I still don't understand why the anonymous function doesn't work.

what does this line means? Can somebody help me by explaining consumer.Received += (model, ea)

this is snip of code. I m not getting "consumer.Received += (model ,ea) =>
As of the docs Received is an event within the EventingBasicConsumer-class. This means that you can register for the event by adding an event-handler to it.
consumer.Recieved += (model, args) => { /*
do whatever you want when the event is triggered
*/};
This is some portion of code (more accurate a delegate) that is executed when the event occurs. In your special case you also get some arguments from the event to appropriately react on that event. The first is of type IBasicConsumer and the second of type BasicDeliverEventArgs. Thus the following is identical to the code I´ve written above:
consumer.Recieved += (IBasicConsumer model, BasicDeliverEventArgs args) => { /*
do whatever you want when the event is triggered
*/};
While you often can omit the first one as it´s not needed the second one holds information the caller of the event (the Rabbit-framework in your case) applied to that delegate. So you can use it and display it in a MessageBox for instance.
var body = args.Body;
Alternativly to using an anonymous method (a method without a name as shown above) you can surely use a named one:
consumer.Recieved += MyHandler;
private void MyHandler(IBasicConsumer model, BasicDeliverEventArgs args)
{
// your stuff here
}
Doing so has the advantage that you can easily remove the handler.
consumer.Recieved -= MyHandler;
So your question boils down to what does consumer.Received += (model, ea) => {stuff} do? Its a Lambda function..
well the Received is an event, which clearly has 2 properties, for which the coder has named them model and ea. Which they they use in {stuff}
Previously you could/would have written (and Im making up variable types here but)
consume.Received += mycall;
void mycall(String model, Mything ea)
{
stuff;
}
There are however disadvantages of the lamda, while you can add them on the fly, its not so easy to remove.. where as the older style you can do consume.Received -= mycall;

How to add a more generic event handler to an event at runtime

If I have a type that inherits from EventArgs (lets call it EventArgs1), and a further bunch of classes that inherit from EventArgs1 (lets call them collectively EventArgsX), and then a bunch of events that are are of the type EventHandler<EventArgsX>, if at runtime I am passed the EventInfo for one of these events and I want to add an event handler that expects a second argument of type EventArgs1 (e.g. MyEventHandler(object sender, EventArgs1 e)) how would I do it?
If the event was of type EventHandler<EventArgs1> then I would just do this:
eventInfo.AddEventHandler(this, new EventHandler<EventArgs1>(MyEventHandler));
But this throws an exception when the event is of type EventHandler<EventArgsX>, and since I don't know what EventArgsX is at compile time I can't simply new up an EventHandler<EventArgsX> If I did know which event I was adding the handler to at compile time then this would be entirely acceptable:
MyEvent += MyEventHandler
But I simply can't work out how to do this at runtime. Any suggestions?
I can't simply new up an EventHandler<EventArgsX>
Sure you can, although you need to do it using Delegate.CreateDelegate() and reflection. Assuming MyEventHandler is an instance method on this, you could do it like this:
var eventInfo = …;
EventHandler<EventArgs1> badHandler = MyEventHandler;
var goodHandler = Delegate.CreateDelegate(
eventInfo.EventHandlerType, this, badHandler.Method);
eventInfo.AddEventHandler(this, goodHandler);
UPDATE
I have read the question backwards, essentially; I will leave this answer in case someone else who is trying to do the reverse finds this question.
Basically, you can't do what you're trying to do. An event can't add a delegate if the delegate's EventArgs type is a subclass of the event's declared type. You're trying to use covariance when the input parameter is contravariant.
Assume these classes
class EventArgs1 : EventArgs {}
class EventArgsA : EventArgs1 {}
class EventArgsB : EventArgs1 {}
Consider what would happen if you could add a method void Handle(object sender, EventArgsA args) to an event with the signature void SomeEvent(object sender, EventArgs1 args). The event source might do this:
if (SomeEvent != null)
{
var args = new EventArgsB();
SomeEvent(this, args); //this line is perfectly legal, as EventArgsB inherits from EventArgs1.
}
However, when the runtime gets to this delegate in the event's invocation list, it now has to pass the args object to Handle(object, EventArgsA), which it of course can't do, since an EventArgsB instance is not an EventArgsA instance. A run-time exception would result. In reality, the mismatch is caught when you add the delegate, so the exception is thrown then.

What's the benefits of registering an event handler implicitly

What's the benefits of registering an event as:
void MyMethod()
{
button1.Click += delegate (object sender, EventArgs e)
{
..
}
}
in comparison with:
void MyMethod()
{
button1.Click += new System.EventHandler(this.button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
..
}
UPDATE:
And what about unsubscribing it?
The benefit is that you don't have to come up with a name and a place in your class.
For a light function, tightly coupled to the code that register the event, the short version is more convenient.
Note that you can also exchange delegate for a =>
button1.Click += (object sender, EventArgs e) =>
{
..
}
You can be even more concise:
button1.Click += ( sender, e ) =>
{
};
Syntactically it's cleaner (as long as it doesn't lead to long blocks of code which would be better broken up into named methods).
The inline declaration is a closure, which gives you access to the variables adjacent to the anonymous method.
From: What are 'closures' in .NET?
In essence, a closure is a block of code which can be executed at a
later time, but which maintains the environment in which it was first
created - i.e. it can still use the local variables etc of the method
which created it, even after that method has finished executing.
See also: http://csharpindepth.com/articles/chapter5/closures.aspx
When registering event handler with an anonymous delegate or lambda, you can write shorter code and use closures. But you cannot unsubscribe from the event, and if the event handler code is too long, your code becomes ugly.
It's just about coding style.
Worth mantioning that declaring it like in first case let you to avoid "spaghetti code" and inject into the handler function local variables (if needed) in more natural(human readable way).
To be more clear. By writing like in first case you can:
int x = 0;
System.Windows.Forms.Button button = new System.Windows.Forms.Button();
button.Click += (o,e)=> {
++x;
};
Inside the event handler you can access the local variable declared actually out for the scope of the handler method. For most people it seems "natural", but if you think like a developer it shouldn't be even possible.
Good luck.

what is += (o, arg) => actually achieving?

Sorry to ask all, but I'm an old hand Vb.net guy who's transferring to c#. I have the following piece of code that seems to activate when the (in this case) postAsync method is fired. I just don;t understand what the code is doing (as follows):-
app.PostCompleted +=
(o, args) =>
{
if (args.Error == null)
{
MessageBox.Show("Picture posted to wall successfully.");
}
else
{
MessageBox.Show(args.Error.Message);
}
};
if anyone could explain what the += (o,args) => is actually acheiving I'd be so greatful....
many thanks in advance.
Tim
(o,args) => defines a lambda expression that takes two parameters named o and args. The types of those parameters is inferred according to the type of PostCompleted (if PostCompleted is an EventHandler, then they will be respectively of type Object and EventArgs). The expression's body then follows after the =>.
The result is than added as an handler to PostCompleted.
As such, it's a less verbose way to write:
app.PostCompleted += delegate(object o, EventArgs args)
{
// ...
};
Which is a shorthand for:
void YourHandler(object o, EventArgs args)
{
// ...
}
// ...
app.PostCompleted += YourHandler;
That is an added handler for the PostCompleted event using a lambda expression. It is similar to
app.PostCompleted += MyHandler;
// ...
private void MyHandler(object sender, EventArgs e) {
// ...
}
But when using lambda expressions, you can't detach the handler easily.
It's shorthand for a delegate defining the event handler for the POST completion event:
app.PostCompleted += delegate(object o, EventArgs args) {
// ...
};
See also Anonymous Methods.
Assuming PostCompleted is an event, you are basically creating an event handler using lambda notation.
This code snipped is equivalent to:
app.PostCompleted += delegate (o, args)
{
if (args.Error == null)
{
MessageBox.Show("Picture posted to wall successfully.");
}
else
{
MessageBox.Show(args.Error.Message);
}
};
The vb.net equivalent would look like this:
AddHandler app.PostCompleted, Function(o, args)
''# ...
End Function
Note that this requires Visual Studio 2010/.Net 4, but the C# code works back in Visual Studio 2008/.Net 3.5.
But that's only partly true. In C#, this is a way to define a method as an event handler in one place. In VB.Net, you can use the Handles keyword, and so the actual equivalent might look more like this:
Public Sub App_PostCompleted(ByVal Sender as Object, ByVall e As EventArgs) Handles app.PostCompleted
''#
End Sub
But even that's not completely equivalent, since you gave the method a name and can call it from anywhere. The only reference to the C# code (and thus the only way to call it) is through the event subscription.
The (o,args) => part is a lambda expression, which is an anonymous function.
the += part assigns the lambda expression to be called when the event fires.

Categories