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.
Related
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;
While reading the NSubstitute tutorial i convert the samples written in C# to VB.net to understand the functionality, but I need your support for these (unrelated) statements, which I can't convert despite all the care taken:
1.
calculator().Received().Add(1, Arg.Is(Of Integer)(function(x) new[] {-2,-5,-10}.Contains(x)))
2.
Note: foo is a derived object from an interface with a void method called "SayHello"
foo.When(x >= x.SayHello("World")).Do(x => counter++);
3.
calculator().When(x >= x.Add(-2, -2)).Do(x => { throw new Exception(); });
Note: engine is a derived object from this interface:
public interface IEngine {
event EventHandler Idling;
event EventHandler<LowFuelWarningEventArgs> LowFuelWarning;
event Action<int> RevvedAt;
}
4.
engine.Idling += (sender, args) => wasCalled = true;
5.
engine.Idling += Raise.EventWith(new object(), new EventArgs());
6.
engine.RevvedAt += rpm => revvedAt = rpm;
With your support I hope, I'm able to convert the remaining statements on my own.
Thank you in advance
Michael
It seems you want to convert Lambda's and adding event handlers.
Lambda from c#
.Where(x => x.Foo = 1)
.Do(x => x.Bar())
translates into
.Where(function(x) x.Foo = 1)
.Do(sub(x) x.Bar())
In VB.Net you have to take into account if the Labda is actually performing a function or a sub and code it accordingly.
Adding events in c#
engine.Idling += MyEventHandler
in VB.Net
AddHandler engine.Idling, AddressOf MyEventHandler
VB.Net lets u add the event like this. Removing an event is done by the keyword RemoveHandler
To add to Jeroen's answer, the general format for adding an event handler is:
AddHandler someObject.SomeEvent, SomeDelegate
You can use the AddressOf operator to create a delegate that refers to a named method but that is not the only way. A Lambda also creates a delegate so this:
engine.Idling += (sender, args) => wasCalled = true;
becomes this:
AddHandler engine.Idling, Sub(sender, args) wasCalled = True
Also, this line is not actually adding an event handler:
engine.RevvedAt += rpm => revvedAt = rpm;
so AddHandler won't work. I have never done it myself but I believe that you need to call Delegate.Combine for that:
engine.RevvedAt = [Delegate].Combine(engine.RevvedAt, Sub(rpm) revvedAt = rpm)
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.
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.
If I write something like
myDataModel.ContentLoaded += (o,e) => { DoSomething(); }
When (if ever) is that anonymous delegate removed from the event?
As a quick example, I could write this program
class Program
{
public event EventHandler<EventArgs> MyEvent = delegate { };
static void Main(string[] args)
{
Program p = new Program();
while(true)
{
p.MyEvent += (o, e) => Console.WriteLine("Hello!");
Console.ReadLine();
p.Foo();
}
}
void Foo()
{
MyEvent(this, EventArgs.Empty);
}
}
And the output as I press 'Enter' repeatedly is
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
...and so forth. I could add the line
p.MyEvent -= (o, e) => Console.WriteLine("Hello!");
after p.Foo() but of course it has no effect because I'm removing an entirely different anonymous delegate.
So what's the deal with this? Is there any way of removing these anonymous delegates at all? What are the implications for, say, an asynchronous Silverlight application where I'm pulling data using expressions like
_myDataContext.Load(myQuery, loadOperation =>
{
// do stuff with the data here
}, null);
? I assume that these kinds of callbacks aren't implemented using events, but of course it's impossible(?) to tell.
Are anonymous delegates dangerous if not carefully accounted for?
There is no (easy) way to remove delegates that you didn't first assing to any variable. It doesn't really matter whether they're anonymous or not. You can assign anonymous delegate to a variable and remove it later:
EventHandler eh = (src, e) => Console.WriteLine("Hello");
form.Click += eh;
// At some later point
form.Click -= eh;
Similarly, there is no (easy) way to remove delegate if you register it using:
form.Click += new EventHandler(foo);
The problem with events is that they are only garbage collected when the object that they're attached to is garbage collected (even if the target object that they work with is not referenced from any other part of program and so they cannot do any useful work).
This can be solved using weak events. Instead of removing them explicitly, you use some mechanims that allows GC to deal with them automatically.
It will never be automatically removed from the event.
If you want to unsubscribe an anonymous delegate, check out this question:
Unsubscribe anonymous method in C#