Thursday, January 15

Delegates in .Net

Introduction:

A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method (both static and instance method) inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked. This paper explains the basic concepts of delegates as well as lambda expressions.

Where delegates are used?

• The most common example of using delegates is in events particularly, if the method to be invoked is known only during runtime. For example, consider a scenario where the data provided by the user at runtime decides which method to be invoked. In such cases, delegate is the best solution.

• Suppose a sequence of methods to be invoked when an event occurred, then a single delegate can be used to invoke multiple methods.

• If the caller has no need to access other properties, methods, or interfaces on the object implementing the method then delegates can be used.

• The situations where methods to be passed as parameters.

• If a class needs more than one implementation of the method then delegates can be used.

Calling a function directly or without using a delegate

In normal situations, we can invoke the method directly as shown below:
class A
{
public void print()
{
Console.WriteLine("print method");
}
}
class B
{
static void Main(string[] args)
{
A a = new A();
a.print();
Console.Read();
}
}

Basics of delegates:

With delegates, it is possible to reference any method which has the same signature as that of the delegate regardless of the internal functionality of the method. The signature of the delegate consists of return type and parameters of the delegate. An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method's argument types and return type match that of delegate. Delegates are type-safe function pointer which means that the parameter list and the return type are known.

There are three steps in defining and using delegates:

• Declaration
• Instantiation
• Invocation

Declaring delegate:

The signature of a simple single cast delegate is shown below:

delegate returntype identifier ([parameters]);

where

• delegate: to define a delegate we use a key word delegate followed by the method signature the delegate represents

• return type: the return type of the function.

• identifier: The delegate name.

• parameters: The Parameters, that the function takes.

For example:

public delegate void simpledelegate();

This declaration defines a delegate named simpledelegate(), which will encapsulate any method that takes no parameters and returns no value.

public delegate int del(int x, int y);

This declaration defines a delegate named del, which will encapsulate any method that takes two parameters int and int and returns a int.

Instantiating of delegate:

Here, object of the delegate is created using new keyword and also the method to be invoked is passed.

The format of instantiating a delegate is as follows:

Delegatename object = new Delegatename(method);

For exampple:

simpledelegate simple = new simpledelegate(a.method1);

where the signature of the method, a.method1 should exactly match with the signature of simpledelegate.

Invoking delegate:

To invoke the method referred to by the delegate; the delegate instance is used, as if it were the method.

simple();

Sample Program 1:

To invoke a simple static method using delegate:-

//declaring delegate
delegate void simpledelegate();
static class mainclass
{
public static void method1()
{
Console.WriteLine("method 1");
}

static void Main(string[] args)
{
//instantiating the delegate
simpledelegate simple = new simpledelegate(method1);

//invoking delegate
simple();

Console.Read();
}
}

Output:

method 1

Since method1() is a static method, it can be directly encapsulated within the delegate.

Sample Program 2:

To invoke a non-static method:-

class mainclass
{
//declaring delegate
public delegate void simpledelegate();

public void method1()
{
Console.WriteLine("method 1");
}

static void Main(string[] args)
{
// creating object of class A
A a = new A();

//instantiating the delegate
simpledelegate simple = new simpledelegate(a.method1);

//invoking delegate
simple();

Console.Read();
}
}

Output:

method 1

Since the method to be encapsulated is not a static method, use the object reference of the class while instantiating the delegate.

Sample Program 3:

Invoking a method having arguments:-

//declaring delegate with return type and parameter
delegate int parameterdelegate(int x,int y);

class mainclass
{
public int add(int a, int b)
{
return a + b;
}

static void Main(string[] args)
{
//creating object of class A
mainclass a = new mainclass();

//instantiating the delegate
parameterdelegate del = new parameterdelegate(a.add);

//invoking delegate
int i=del(2, 3);

Console.WriteLine("Sum is: "+i);

Console.Read();
}
}

Output:

Sum is 5

While instantiating a delegate only, method is passed not the parameters to the method. The parameters to the method are passed only when the delegate is invoked.

Delegate in depth:

1)Declaration:

When we declare a new delegate type (like simpledelegate) the C# compiler generates a class called simpledelegate that derives the System.MultipcastDelegate. Since nested class is possible in C#, delegates can be declared either within a class or outside. The delegate class created by compiler is as follows:

public sealed class simpledelegate : System.MulticastDelegate
{
public simpledelegate(object target, int method);
public virtual void Invoke();
public virtual IAsyncResult BeginInvoke(AsyncCallback callback, object obj);
public virtual void EndInvoke(IAsyncResult result);
}

simpledelegate (object target, int method):

The Constructor method of this class takes two arguments. The first is an object reference of the type that defined the instance method that the delegate refers to, and the second is an int value of the function pointer to the method that the delegate encapsulates.

Invoke():

This method is used for synchronous call The Invoke () method has the same signature as the delegate declaration. This method is used to call the delegate's encapsulated method. By defining a delegate, actually we are providing the signature for the method that can be encapsulated. In other words, the delegate can't refer to a method with a different signature than the one that it is created with.

BeginInvoke():

This method is used for asynchronous calls. BeginInvoke() takes two parameters. The first one will be a delegate of type AsyncCallback and second will be the delegate that we declared. AsyncCallback is a delegate for a method that returns void and takes a single argument, an object of type IAsyncResult. The framework defines this interface and CLR will call the encapsulated method with an object that implements IAsyncResult.

EndInvoke():

This method also is used for asynchronous calls. It returns the value of the called method and assigns this value to the local variable used in the program.
The C# compiler generates the sealed class with the three virtual methods and a constructor, but it doesn't generate any implementation for those methods because they have to be implemented by the Common Language Runtime. It saves a lot of time by providing the delegate keyword which we can use to generate a class based on the System.MultipcastDelegate.

2)Instantiating delegate:

It is already mentioned that the generated class constructor has two parameters. If the encapsulating method is a static one, then first parameters of the constructor i.e. object will be a null value otherwise it holds object reference of the encapsulating method.

3)Invoking delegate:

In order to call the delegate's encapsulated method, Invoke () method of the delegate class should be invoked. Since it is not possible to call this method directly, we use the object reference and pass the arguments to it.

For example:

del(2, 3);

where del is the instance of a delegate.

In the MSIL code, invoking delegate is translated to a call to invoke the encapsulated method as given below:

Callvirt instance int32 ClassLibrary.Processor:: Invoke(int32,int32)

Multicast delegates:

It is possible to wrap more than one method in a delegate. This is known as a multicast delegate. To add a method to the invocation list of a delegate object, simply make use of the overloaded += operator, and to remove a method from the invocation list, use of the overloaded operator - =. While invoking a multicast delegate, it will call all the functions it wraps in the order specified. If the Multicast delegate contains methods with return type then return value of the last method in the invocation list only be obtained.

Sample Program 4:

Multicast delegate: - More than one method with no return

//declaring delegate
delegate void multicast (string s);

class mainclass
{
//method 1
public void method1(string str)
{
Console.WriteLine("string passed to method 1 is: " + str);
}

//method 2
public void method2(string s)
{
Console.WriteLine("string passed to method 2 is: "+s);
}

static void Main(string[] args)
{
//creating object of class A
mainclass a = new mainclass();

//instantiating the delegate
multicast multi = new multicast(a.method1);
multi += new multicast(a.method2);

//invoking delegate
multi("hello");

Console.Read();
}
}

Output:

string passed to method 1 is: hello
string passed to method 2 is: hello

While invoking the delegate, the encapsulated methods are executed in the specified order and the argument passed to both of the methods is hello.

Sample Program 5:

//declaring delegate
delegate string multicast (string s);

class mainclass
{
//method 1
public string method1(string str)
{
Console.WriteLine("string passed to method 1 is: " + str);
return "method 1";
}

//method 2
public string method2(string s)
{
Console.WriteLine("string passed to method 2 is: "+s);
return "method 2";
}

static void Main(string[] args)
{
//creating object of class A
mainclass a = new mainclass();

//instantiating the delegate
multicast multi = new multicast(a.method1);
multi += new multicast(a.method2);

//invoking delegate
Console.WriteLine("string returned: "+multi("hello"));

Console.Read();
}
}

Output:

string passed to method 1 is: hello
string passed to method 2 is: hello
string returned: method 2

Multicast delegate in depth:

Actually, behind the scenes the method Combine () is used to perform the creation of a multicast delegate which returns a new delegate instance. That there is an additional field in a MulticastDelegate called prev which refers to another MulticastDelegate. The method Delegate.Combine combines the two delegates and makes second’s prev field point to first. It then returns the head of the linked list. Thus, when a delegate is added to a multicast delegate, the MulticastDelegate class creates a new instance of the delegate type, stores the object reference and the pointer for the target method into the new instance, and adds the new delegate instance as the next item in a list of delegate instances. In effect, the MulticastDelegate class maintains a linked list of delegate objects. A chain of delegate target is thus created. Invoking the delegate invokes each delegate (which in turn calls its encapsulated method) in the same order that it has been added to the linked list. The IL code of multicast delegate looks like this:

call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class

[mscorlib]System.Delegate, class [mscorlib]System.Delegate)

Covariance and Contravariance:

This is the new feature in c# 2.0. Covariance and contravariance provide a great degree of flexibility when matching delegate methods with delegate signatures. Covariance allows a method with a derived return type to be used as the delegate, and contravariance allows a method with derived parameters to be used as the delegate.

Covariant delegate:

A delegate with return type of base class can encapsulate a method having derived type as return type. This is called covariance. Since the method's return type is more specific than the delegate signature's return type, it can be implicitly converted.

Sample Program 6:

class animal
{
//constructor
public animal()
{
}
}

class dog : animal
{
//constructor
public dog()
{
}
}

//delegate declaration with base class return type
delegate animal covariance();

class mainclass
{
// method with base class return type
public animal animalmethod()
{
Console.WriteLine("animal method");
animal a = new animal();
return a;
}

//method with derived class return type
public dog dogmethod()
{
Console.WriteLine("dog method");
dog d = new dog();
return d;
}

public static void Main()
{
mainclass obj=new mainclass();

//multicasting
covariance cov = new covariance(obj.animalmethod);
cov += new covariance(obj.dogmethod);

//invoking delegate
cov();

Console.Read();
}
}
Output:

animal method
dog method

Contravariant delegate:

When a delegate method signature has one or more parameters of types that are derived from the types of the method parameters, that method is said to be contravariant. As the delegate method signature parameters are more specific than the method parameters, they can be implicitly converted when passed to the handler method.

Sample Program 7:

delegate void contravariance(Dog d);

class Animal
{
public void eat(Animal m)
{
Console.WriteLine("Animal eats");
}
}

class Dog : Animal
{
public void run(Dog d)
{
Console.WriteLine("Dog runs");
}
}

class Program
{
static void Main(string[] args)
{

Animal parent = new Animal();
Dog child = new Dog();

contravariance contDelegate = new contravariance(child.run);
contDelegate += new contravariance(parent.eat);
contDelegate(child);

Console.Read();

}
}

Output:
Dog runs
Animal eats

Here class Dog inherits class Animal.Also; the delegate contravariance has a parameter of type Dog. By contravariant property of delegate, it is possible to encapsulate any method having parameter of type matching with any of the base classes of Dog.

Asynchronous delegate:

In normal scenario, when a method is invoked using delegate, it will block the caller thread until the method completes. This way of calling a method is known as synchronous. But if there is a long running process that will be executed when we invoke the method, for example:

public int MyMethod(int x)
{
Thread.Sleep(10000);
return x*x;
}

So the caller thread has to wait till that long execution gets completed. There comes the importance of asynchronous delegate.

In asynchronous delegates, caller thread will be executed simultaneously with the execution of the invoked method. When a thread makes an asynchronous call to a method, the call returns immediately. The caller thread is not blocked; it is free to perform some other task. The infrastructure obtains a thread for the method invocation and delivers the in parameters passed by the calling code. This asynchronous thread can then run the method in parallel to the calling thread. If the method generates some data and returns this value, the calling thread must be able to access this data.

The .NET asynchronous infrastructure supports two mechanisms:

• The calling thread can either ask for the results.

• The infrastructure can deliver the results to the calling thread when the results are ready.

An asynchronous approach may be better in certain situations, such as when a program needs to send out requests to multiple Web services.

Sample Program 8:

delegate int asynchronousdel(int a);
class A
{
public int longmethod(int x)
{
Thread.Sleep(9999);
return x * x;
}
}

class mainclass
{
public static void Main()
{
A a = new A();
asynchronousdel del = new asynchronousdel(a.longmethod);

IAsyncResult asyn = del.BeginInvoke(5, null, null);

//write whatever operations to be executed simultaneously
Console.WriteLine("processing continues");

int result = del.EndInvoke(asyn);

Console.WriteLine("result is {0}",result);
Console.Read();
}
}

Output:

processing continues

result is 25

Here instead of invoking our method directly, use the delegate to call BeginInvoke() method that returns an IAsyncResult object, then pass this object to the EndInvoke() method then EndInvoke() provide the return value.

When BeginInvoke() is invoked the encapsulated methods are queued to start on another thread. BeginInvoke() doesn't return the return value of the underlying methods. When calling BeginInvoke() pass all the parameters of the original method, plus two parameters, the first can be used in callback and the other is a state object. if it is not needed then just pass a null reference as shown in sample program. Instead it returns an IAsyncResult object that you can use to determine when the asynchronous operation is complete. To get the results, pass the IAsyncResult object to the EndInvoke() method of the delegate. EndInvoke() waits for the operation to complete if it hasn't already finished and then provide the return value.

Asynchronous multicast delegate:

It is not possible to execute a multicast delegate asynchronously. Hence each method in the invocation list to be invoked explicitly but using GetInvokationList().

Sample Program 9:

class A
{
public void method1()
{
Console.WriteLine("method 1");
Thread.Sleep(1000);
}
public void method2()
{
Console.WriteLine("method 2");
Thread.Sleep(1000);
}
public void method3()
{
Console.WriteLine("method 3");
Thread.Sleep(1000);
}
}

delegate void asynchronousdel();

class mainclass
{
public static void Main()
{
A a = new A();
asynchronousdel del = new asynchronousdel(a.method1);
del += new asynchronousdel(a.method2);
del += new asynchronousdel(a.method3);


//asynchronous invokation of multicast delegate*********

foreach (asynchronousdel d in del.GetInvocationList())
{
IAsyncResult asyn = d.BeginInvoke(null, null);

Console.WriteLine("Process in progress");

d.EndInvoke(asyn);
}

Console.Read();
}
}

Asynchronous delegate in depth:

Calling a method onto a worker thread is achieved by calling BeginInvoke() on a delegate that wraps the method. This tells the delegate to queue the method invocation onto the Thread Pool. Also, the return type of BeginInvoke() is IAsyncResult. The definition of IAsyncResult looks like this:

public interface IAsyncResult
{
object AsyncState { get; }
WaitHandle AsyncWaitHandle { get; }
bool CompletedSynchronously { get; }
bool IsCompleted { get; }
}

If the asynchronous method has not completed, EndInvoke will block until it completes. This may be the required behavior--that the caller gets on with other work and then calls EndInvoke () when the results are needed.

There are four patterns in asynchronous delegate execution:

• Polling
• Waiting for Completion
• Completion Notification
• "Fire and Forget"

Polling:

One of the members of IAsyncResult, IsCompleted returns true if the asynchronous method execution completes otherwise it will be false. IsCompleted can, therefore, be used to assess whether the long-running calculation is finished. The main thread then polls until execution of the method completes.

Sample Program 10:

class A
{
public void method1()
{
Console.WriteLine("method 1");
Thread.Sleep(10);
}
public void method2()
{
Console.WriteLine("method 2");
Thread.Sleep(10);
}
public void method3()
{
Console.WriteLine("method 3");
Thread.Sleep(10);
}
}

delegate void asynchronousdel();

class mainclass
{
public static void Main()
{
A a = new A();
asynchronousdel del = new asynchronousdel(a.method1);
del += new asynchronousdel(a.method2);
del += new asynchronousdel(a.method3);

foreach (asynchronousdel d in del.GetInvocationList())
{

IAsyncResult asyn =d.BeginInvoke(null, null);

//checking the property IsCompleted

while (!asyn.IsCompleted)
{
Console.WriteLine("\noperation proceeds");
}

d.EndInvoke(asyn);

Console.WriteLine("\nOperation completed");

Console.ReadKey();
} // end of foreach

} // end of main method

} // end of mainclass


Waiting with timeout:

The second property in the IAsyncResult interface, AsyncWaitHandle, is used for this pattern of execution. Here, the caller thread is made to wait until the method completes execution by passing it to one of the WaitHandle class’ methods, WaitAll, WaitOne, or WaitAny. This is useful if caller thread sends several asynchronous method calls to operate in parallel and would like to make sure they all complete before continuing caller thread, especially if the main program’s continued operation is dependent upon the results of one or more of these calls. It is, therefore, possible to make the asynchronous call on to another thread and then wait for it to complete--but then timeout the call if it carries on too long (greater than time out interval).

Sample Program 11:


A simple program showing waiting with timeout asynchronous pattern:

delegate int timeoutdel(int a,int b);

class A
{
public int add(int x, int y)
{
Thread.Sleep(10);
return x + y;
}
public int multiply(int x, int y)
{
Thread.Sleep(10);
return x * y;
}
}
class mainclass
{
public static void Main()
{
A a = new A();
timeoutdel del = new timeoutdel(a.add);
del += new timeoutdel(a.multiply);

foreach (timeoutdel d in del.GetInvocationList())
{
IAsyncResult asyn = d.BeginInvoke(2,3,null, null);
if (asyn.AsyncWaitHandle.WaitOne(20, true))
{
int i=d.EndInvoke(asyn);
Console.WriteLine("\n Result is: "+i);
Console.WriteLine("\n operation completed.......");
}
else
{
Console.WriteLine("\n Timeout.......");
}
Console.ReadKey();
}
}
}

Output:

Result is:5
operation completed.......
Result is:6
operation completed.......

The main thread waits for 20 milliseconds for the method to return; if it doesn't return in that time, a message “Timeout.......” is printed out to the console window. If it return within the timeout time result is printed to the console window along with the message “operation completed.......”

Completion Notification:

So far, the last two parameters of BeginInvoke have been passed as null: the AsyncCallback delegate and the System.Object for the asynchronous state. These two parameters are used to provide a callback mechanism that will be invoked when the call completes. The definition of AsyncCallback delegate is:

delegate void AsyncCallback(IAsyncResult a);

So the signature of the method that receives completion notification should be same as above. This method is wrapped in an instance of the AsyncCallback and is passed when we invoke BeginInvoke() method as shown below:

class mainclass
{
static void Main()
{
completiondel cmp = new completiondel(add);

IAsyncResult ar = cmp.BeginInvoke(2, 3, new syncCallback(callback), null);
// Do some work
}

void callback(IAsyncResult ar)
{
// Details to follow shortly
}

static void add(int x, int y)
{
// calculate the sum
}
}

MyCallback will now be called on completion of the completiondel invocation. However, to do anything useful, MyCallback needs to be able to call EndInvoke on the completiondel delegate, but all it has access to, is the IAsyncResult.
In the definition of IAsyncResult, there is a property, AsyncState, which returns a System.Object. This is the object passed as the last parameter of BeginInvoke. In the above sample, null is passed as the System.Object which will throw nullreference exception. So adding some more code to the previous code, we can call EndInvoke as follows:

Sample Program 12:

delegate int completiondel(int a,int b);
class mainclass
{
public static void Main()
{
mainclass obj = new mainclass();
completiondel del = new completiondel(obj.add);
IAsyncResult asyn = del.BeginInvoke(2, 3,obj.callback,del);
Console.WriteLine("hello"); //executes simultaneously
Console.ReadKey();
}
public int add(int x, int y)
{
Console.WriteLine("add method");
return x + y;
}
public void callback(IAsyncResult a)
{
Console.WriteLine("callback method");
completiondel cmp = (completiondel)a.AsyncState;
int result=cmp.EndInvoke(a);
Console.WriteLine("Sum is: "+result);
Console.WriteLine("Operation completed..........");
}
} //end of mainclass

Output:

Hello
add method
callback method
Sum is: 5
Operation completed..........

Fire and forget:

The Fire and Forget pattern is used when the return value and returned parameters of the call are not required, and when there is no need to synchronize with the asynchronously executing method. In this case, the caller simply needs to call BeginInvoke, passing any normal and ref parameters, and null for the callback and asyncState.

This pattern is excellent where the requirement is solely to execute the functionality on a separate thread so that the primary thread can resume its main task, having no regard to the asynchronously executing method.

Sample Program 13:

delegate int firedel(int a, int b);
class mainclass
{
public static void Main()
{
mainclass obj = new mainclass();
firedel del = new firedel(obj.add);
del.BeginInvoke(2, 3, null, null);
// do some stuff
Console.WriteLine("Operations in main method");
Console.ReadKey();
}
public int add(int x, int y)
{
// do some stuff
return x + y;
}
}
Output:

Operations in main method

But, it is recommended that EndInvoke() should be called for a corresponding BeginInvoke() even if the return values of asynchronous calls are not needed. Otherwise, Microsoft says that they may cause resource leakage now or in future.

Disadvantages of asynchronous delegates:

As the asynchronous methods run on thread pool threads, there are certain tasks for which asynchronous delegates are not appropriate.

Anonymous delegate:

Anonymous delegates in C# are extremely useful feature in C# 2.0 that allows defining an anonymous (i.e. nameless) method called by a delegate. C# 2.0 introduced a new feature, an anonymous method that allows declaring the method code inline. By using anonymous methods, we reduce the coding overhead in instantiating delegates by eliminating the need to create a separate method. By specifying a code block in the place of a delegate can be useful in a situation when having to create a method might seem an unnecessary overhead.

Sample Program 14:

Simple anonymous delegate:

class mainclass
{
delegate void anondel();
public static void Main()
{
anondel del = new anondel(delegate()
{
Console.WriteLine("anonymous method...");
});
del();
Console.ReadKey();
}
}

Output:

anonymous method...

Sample Program 15:

Multicasting with anonymous delegate:
using System;
using System.Collections.Generic;
using System.Text;


namespace Delegate_example
{
delegate void anonymousdelegate();

class mainclass
{
public void somemethod()
{
Console.WriteLine("some method");
}

public static void staticmethod()
{
Console.WriteLine("static method");
}

public static void Main()
{
//adding anonymous method to a delegate
anonymousdelegate anon = new anonymousdelegate(delegate
{
Console.WriteLine("anonymous method 1");
});

//multicasting another anonymous method
anon += new anonymousdelegate(delegate
{
Console.WriteLine("anonymous method 2");
});

mainclass obj = new mainclass();

//multicasting an instance method
anon += new anonymousdelegate(obj.somemethod);

//multicasting a static method
anon += new anonymousdelegate(staticmethod);

anon();
Console.Read();
}
}
}

Output:

anonymous method 1
anonymous method 2
some method
static method


Restrictions to anonymous method:

• Cannot use jump instructions such as goto, break etc which takes control out of the anonymous method. (the control should be within the method only)

• Cannot pass parameters of type ref or out to the method.

• The scope of the parameters of an anonymous method is within the anonymous-method-block only.

• The local variables declared outside the anonymous method can be used inside the method and such a variable is known as outer or captured variables of the anonymous method.

Anonymous delegate in depth:

When a program having anonymous delegate is compiled, a named nested class is added to the class that indirectly contained (within one of the methods within the class) the anonymous delegate. The class exposes some surface area that is accessed from the parent class. The class is actually private, which means it cannot be accessed from anywhere but the parent class. There is a default constructor, which does nothing. There is a method that is the anonymous delegate transformed into a regular named method. Anonymous delegates are a C#, not a CLR feature, so the CLR does need a named method to call. Lastly, there are a set of fields exposed on this compiler-generated class.

Anonymous methods can be specified with parameters enclosed in parenthesis, or without parameters, with empty parenthesis. When parameters are specified, the signature of the anonymous method must match the signature of the delegate. When the delegate has no parameters, empty parenthesis are specified in the anonymous method declaration. When an anonymous method is declared without parenthesis, it can be assigned to a delegate with any signature.

Sample Program 16:

class mainclass
{
delegate void anondel(string s);

public static void Main()
{
anondel del = new anondel(delegate
{
Console.WriteLine("Anonymous delegate");
});

del("hello");

Console.ReadKey();
}
}

Output:

Anonymous delegate

Here there is no paranthesis after delegate keyword hence the anonymous method can be assigned to a delegate called anondel which is having a different signature.

Conclusion:

This paper focused on delegates and explained why they are valuable to C# application development. Delegates allow you to refer to methods to dynamically invoke code and call multiple methods together. When executed, each member of a delegate's invocation list is executed synchronously, in the order they were added or asynchronously. A delegate's invocation list can be manipulated by adding and removing delegates.

2 comments:

Anonymous said...

Greetings! I know this іѕ kinԁa off toρic but І'd figured I'd ask.

Would you bе interestеd in exсhаnging
links or mаybе gueѕt authoring a blog articlе оr
vісe-vеrѕa? Ϻy blog diѕcussеs a lot of the ѕame toρіcs
as yours and I fеel we сould gгeatlу bеnefit from еach otheг.
Ιf yоu are intегеsteԁ feel frеe to ѕend me an email.
I loоk foгwaгd to hеaring frоm you!
Superb blog by the wау!

my site dallas tx seo company

Anonymous said...

İstanbul Travel Guide

Traffic Exchange

Free Backlink

Website Stats

Pagerabk Check

Webmaster Tools