C# delegate in one word

Untitled

Delegates are basically a cleaner, easier function pointer. Any place where function pointers were used in C++, you can think delegate.

Advantages to using them in design:

  • Can lead to easy reuse of code
  • Can provide a great amount of flexibility in your designs
  • Allow you to develop libraries and classes that are easily extensible, since it provides an easy way to hook in other functionality (for example, a where clause in LINQ can use a delegate [Func] to filter on, without having to write new code in the Where method

Potential disadvantages:

  • They ~can~, particularly if used naively, lead to code that is more difficult to read
  • The can introduce behavior into your component that is unexpected, since 3rd party code out of your control will get called (For example, if somebody attaches a delegate to one of your events that causes an infinite loop, it can make your class look bad, even though it has nothing to do with you)

5 10

Delegates serve three purposes:

  1. A simplified implementation of the Observer pattern
  2. A simplified implementation of callbacks
  3. Anonymous (non-reusable) blocks of code

Observer

CallBack

Anonymous non-reusable code

In all cases, it’s just a matter of providing conciseness.

Delegates

This part of the C# tutorial is dedicated to delegates.

A delegate is a form of type-safe function pointer
used by the .NET Framework. Delegates are often used to implement
callbacks and event listeners. A delegate does not need to know
anything about classes of methods it works with.

A delegate is a reference type. But instead of referring to an object,
a delegate refers to a method.

Delegates are used in the following cases:

  • Event handlers
  • Callbacks
  • LINQ
  • Implementation of design patterns

There is nothing that is done with delegates that cannot be done
with regular methods. Delegates are used because they bring
several advantages. They foster flexibility of the application
and code reuse. Like interfaces, delegates let us decouple and
generalize our code. Delegates also allow methods to be passed as parameters.
When we need to decide which method to call at runtime, we use
a delegate. Finally, delegates provide a way of specializing behavior
of a class without subclassing it. Classes may have complex generic behavior
but are still meant to be specialized. Classes are specialized either
through inheritance or via delegates.

Using delegates

We will have some simple examples showing how to use delegates.

We declare a delegate, create an instance of the delegate and
invoke it.

This is our delegate declaration. It returns no value and takes no
parameters.

We create an instance of the delegate. When called, the delegate will
invoke the static Callback() method.

We call the delegate.

This is the output.

We can use a different syntax for creating and using a delegate.

We can save some typing when creating an instance of a delegate.
This was introduced in C# 2.0.

This is another way of creating a delegate. We point directly to the
method name.

A delegate can point to different methods over time.

In the example we have one delegate. This delegate is used to point
to two methods of the Person class. The methods are called with
the delegate.

The delegate is created with a delegate keyword.
The delegate signature must match the signature of the method being called
with the delegate.

We create an instance of a new delegate that points to the
ShowFirstName() method. Later we call the method
via the delegate.

Both names are printed via the delegate.

Multicast delegate

Multicast delegate is a delegate which holds a
reference to more than one method. Multicast delegates must contain only
methods that return void, else there is a run-time exception.

This is an example of a multicast delegate.

Our delegate will take two parameters. We have
an Oper class which has two static methods. One
adds two values the other one subtracts two
values.

We create an instance of our delegate. The delegate
points to the static Add() method of the Oper class.

We plug another method to the existing delegate instance.
The first call of the delegate invokes two methods.

We remove one method from the delegate. The second call of the
delegate invokes only one method.

This is the output of the multicast.exe program.

Anonymous methods

It is possible to use anonymous methods with delegates.

We can omit a method declaration when using an anonymous method
with a delegate. The method has no name and can be invoked only
via the delegate.

Here we create a delegate, that points to an anonymous method. The
anonymous method has a body enclosed by { } characters, but it has
no name.

Delegates as method parameters

Delegates can be used as method parameters.

We have a DoOperation() method which takes a delegate as a parameter.

This is a delegate declaration.

This is DoOperation() method implementation. The third parameter is a
delegate. The DoOperation() method calls a method which is passed to
it as a third parameter.

We call the DoOperation() method. We pass two values and a method to it.
What we do with the two values depends on the method that we pass. This
is the flexibility that come with using delegates.

Events

Events are messages triggered by some action. A click on a button or
a tick of a clock are such actions. The object that triggers an event
is called a sender and the object that receives the event is called
a receiver.

By convention, event delegates in the .NET Framework have two parameters:
the source that raised the event and the data for the event.

We have a simple example in which we create and launch an event.
An random number is generated. If the number equals to 5 a FiveEvent
event is generated.

An event is declared with a event keyword.

Here we plug the event called FiveEvent to the
Callback method. In other words, if the ValueFive
event is triggered, the Callback() method is executed.

When the random number equals to 5, we invoke the OnFiveEvent() method.
In this method, we raise the FiveEvent event. This event carries no arguments.

The output of the program might look like this.

Complex event example

Next we have a more complex example. This time we will send some
data with the generated event.

We have four classes. The FiveEventArgs carries some data with the
event object. The FEvent class encapsulates the event object. The
RandomEventGenerator class is responsible for random number generation. It is the
event sender. Finally, the ComplexEvent is the main application class.

The FiveEventArgs carries data inside the event object. It inherits from the
EventArgs base class. The count and time members are
data that will be initialized and carried with the event.

If the generated random number equals to 5, we instantiate the
FiveEventArgs class with the current count and DateTime values.
The count variable counts the number of times this event was generated.
The DateTime value holds the time when the event was generated.

This is a sample output of the complexevent.exe program.

Predefined delegates

The .NET framework has several built-in delegates that a reduce the
typing needed and make the programming easier for developers.

An action delegate encapsulates a method that
has no parameters and does not return a value.

Using predefined delegates further simplifies programming. We do not need
to declare a delegate type.

We instantiate an action delegate. The delegate points to the ShowMessage()
method. When the delegate is invoked, the ShowMessage() method is executed.

There are multiple types of action delegates. For example, the Action<T>
delegate encapsulates a method that takes a single parameter and does not return a value.

We modify the previous example to use the action delegate
that takes one parameter.

We create an instance of the Action<T> delegate and
call it with one parameter.

Predicate delegate

A predicate is a method that returns true or false. A predicate delegate is a
reference to a predicate. Predicates are very useful for filtering lists of values.

We have a list of integer values. We want to filter all numbers that
are bigger than three. For this, we use the predicate delegate.

This is a generic list of integer values.

We create an instance of a predicate delegate. The delegate
points to a predicate, a special method that returns true
or false.

The FindAll() method retrieves all the elements that match the
conditions defined by the specified predicate.

The predicate returns true for all values that are greater than
three.

This part of the C# tutorial was dedicated to the delegates.

Sample Code :

class Program
{
//step1 : Define The Delegate
delegate void PrinterQueue(string text,DateTime date);
static string Sep = “\n********************\n”;
static void Main(string[] args)
{

//step2 : intialize the delegate
PrinterQueue myprinter = new PrinterQueue(ColorPrinter);

//or step : multi cast initialization appending
myprinter += new PrinterQueue(BWPrinter);
myprinter += new PrinterQueue(PointPrinter);

string T = “My text tjeiojtioejio jioejo i”;
DateTime Dt = DateTime.Now;

// CAll delegate and every function linked to it
myprinter(T, Dt);

Console.ReadKey();
}

static void ColorPrinter(string t,DateTime dt)
{

Console.WriteLine(“Color\n” + t + “\n” + dt + Sep);

}

static void BWPrinter(string t, DateTime dt)
{

Console.WriteLine(“Black and White\n” + t + “\n” + dt + Sep);

}

static void PointPrinter(string t, DateTime dt)
{

Console.WriteLine(“Point \n” + t + “\n” + dt + Sep);

}

}

While delegate is function pointer between object type and pointer type which is consider as unsafe reference type we have the pointer type as in what we have in c language

C# also supports pointers in a limited extent. A pointer is nothing but a variable that holds the memory address of another type. But in C# pointer can only be declared to hold the memory address of value types and arrays. Unlike reference types, pointer types are not tracked by the default garbage collection mechanism. For the same reason pointers are not allowed to point to a reference type or even to a structure type which contains a reference type. We can say that pointers can point to only unmanaged types which includes all basic data types, enum types, other pointer types and structs which contain only unmanaged types. 

Declaring a Pointer type

The general form of declaring a pointer type is as shown below        

type *variable_name; 

Where * is known as the de-reference operator. For example the following statement

int *x ; 

Declares a pointer variable x, which can hold the address of an int type. The reference operator (&) can be used to get the memory address of a variable. 

int x = 100;

The &x gives the memory address of the variable x, which we can assign to a pointer variable 

int *ptr = & x;.
Console.WriteLine((
int)ptr) // Displays the memory address
Console.WriteLine(*ptr) // Displays the value at the memory address.

Unsafe Codes 

The C# statements can be executed either as in a safe or in an unsafe context. The statements marked as unsafe by using the keyword unsafe runs out side the control of Garbage Collector. Remember that in C# any code involving pointers requires an unsafe context. 

We can use the unsafe keyword in two different ways. It can be used as a modifier to a method, property, and constructor etc. For example

// Author: rajeshvs@msn.com
using System;
class MyClass
{
public unsafe void Method()
{
int x = 10;
int y = 20;
int *ptr1 = &x;
int *ptr2 = &y;
Console.WriteLine((
int)ptr1);
Console.WriteLine((
int)ptr2);
Console.WriteLine(*ptr1);
Console.WriteLine(*ptr2);
}
}
class MyClient
{
public static void Main()
{
MyClass mc = 
new MyClass();
mc.Method();
}
}

The keyword unsafe can also be used to mark a group of statements as unsafe as shown below.

// Author: rajeshvs@msn.com
//unsafe blocks
using System;
class MyClass
{
public void Method()
{
unsafe
{
int x = 10;
int y = 20;
int *ptr1 = &x;
int *ptr2 = &y;
Console.WriteLine((
int)ptr1);
Console.WriteLine((
int)ptr2);
Console.WriteLine(*ptr1);
Console.WriteLine(*ptr2);
}
}
}
class MyClient
{
public static void Main()
{
MyClass mc = 
new MyClass();
mc.Method();
}
}

Pinning an Object

The C# garbage collector can move the objects in memory as it wishes during the garbage collection process. The C# provides a special keyword fixed to tell Garbage Collector not to move an object. That means this fixes in memory the location of the value types pointed to. This is what is known as pinning in C#. 

The fixed statement is typically implemented by generating tables that describe to the Garbage Collector, which objects are to remain fixed in which regions of executable code. Thus as long as a Garbage Collector process doesn’t actually occur during execution of fixed statements, there is very little cost associated with this. However when a Garbage Collector process does occur, fixed objects may cause fragmentation of the heap. Hence objects should be fixed only when absolutely necessary and only for the shortest amount of time.

Pointers & Methods

The points can be passed as argument to a method as showing below. The methods can also return a pointer.

// Author: rajeshvs@msn.com
using System;
class MyClass
{
public unsafe void Method()
{
int x = 10;
int y = 20;
int *sum = swap(&x,&y);
Console.WriteLine(*sum);
}
public unsafe int* swap(int *x, int *y)
{
int sum;
sum = *x + *y;
return &sum;
}
}
class MyClient
{
public static void Main()
{
MyClass mc = 
new MyClass();
mc.Method();
}
}

Pointers & Conversions

In C# pointer types do not inherit from object and no conversion exists between pointer types and objects. That means boxing and un-boxing are not supported by pointers. But C# supports conversions between the different pointer types and pointer types and integral types. 

C# supports both implicit and explicit pointer conversions within un-safe context. The implicit conversions are

  1. From any type pointer type to void * type.
  2. From null type to any pointer type.

The cast operator (()) is necessary for any explicit type conversions. The explicit type conversions are

  1. From any pointer type to any other pointer type.
  2. From sbyte, byte, short, ushort, int, uint, long, ulong to any pointer type.
  3. From any pointer type to sbyte, byte, short, ushort, int, uint, long, ulong types.

For example

char c = ‘R’;
char *pc = &c;
void *pv = pc; // Implicit conversion
int *pi = (int *) pv; // Explicit conversion using casting operator

Pointer Arithmetic

In an un-safe context, the ++ and – operators can be applied to pointer variable of all types except void * type. Thus for every pointer type T* the following operators are implicitly overloaded.

T* operator ++ (T *x);
T* 
operator — (T *x);

The ++ operator adds sizeof(T) to the address contained in the variable and – operator subtracts sizeof(–) from the address contained in the variable for a pointer variable of type T*.

In an un-safe context a constant can be added or subtracted from a pointer variable. Similarly a pointer variable can be subtracted from another pointer variable. But it is not possible to add two pointer variables in C#. 

In un-safe context = =, ! =, <, >, < =, > =  operators can be applied to value types of all pointer types. The multiplication and division of a pointer variable with a constant or with another pointer variable is not possible in C#. 

Stack Allocation 

In an unsafe context, a local declaration may include a stack allocation initialiser, which allocates memory from the call stack.

The stackalloc T[E] requires T to be an unmanaged type and E to be an expression of type int. The above construct allocates E * sizeof(T) bytes from the call stack and produces a pointer of the type T* to the newly allocated block. The E is negative, a System.OverFlowException is thrown. If there is not enough memory to allocate, a System.StackOverflowException is thrown. 

The content of newly allocated memory is undefined. There is no way to implicitly free memory allocated using stackalloc. Instead all stack allocated memory block are automatically discarded once the function returns.

class Test
{
char *buffer =
}

Pointers & Arrays 

In C# array elements can be accessed by using pointer notations.

// Author: rajeshvs@msn.com
using System;
class MyClass
{
public unsafe void Method()
{
int []iArray = new int[10];
for(int count=0; count < 10; count++)
{
iArray[count] = count*count;
}
fixed(int *ptr = iArray)
Display(ptr);
//Console.WriteLine(*(ptr+2));
//Console.WriteLine((int)ptr);
}
public unsafe void Display(int *pt)
{
for(int i=0; i < 14;i++)
{
Console.WriteLine(*(pt+i));
}
}
}
class MyClient
{
public static void Main()
{
MyClass mc = 
new MyClass();
mc.Method();
}
}

Pointers & Structures 

The structures in C# are value types. The pointers can be used with structures if it contains only value types as its members. For example

// Author: rajeshvs@msn.com
using System;
struct MyStruct
{
public int x;
public int y;
public void SetXY(int i, int j)
{
x = i;
y = j;
}
public void ShowXY()
{
Console.WriteLine(x);
Console.WriteLine(y);
}
}
class MyClient
{
public unsafe static void Main()
{
MyStruct ms = 
new MyStruct();
MyStruct *ms1 = &ms;
ms1->SetXY(10,20);
ms1->ShowXY();
}
}

Leave a Reply