Why are delegates used?

All delegates are classes that are implicitly derived from System.Delegate. In general, delegates are useful for two main reasons:
  • Delegates support events.
  • Delegates give your program a way to execute methods at runtime without having to know precisely what those methods are at compile time. This ability is quite useful when you want to create a framework that allows components to be plugged in.
Related Post: Delegates, Multicast Delegates (Multicast Delegates)Anonymous Methods

Anonymous Methods

Anonymous methods allow you to declare a method body without an explicit name. They behave exactly like normal methods behind the scenes, however, there is no way to explicitly call them in your code.

An anonymous method is a block of code that is passed to a delegate. It is created only to be used as a target for a delegate. The main advantage to using an anonymous method is simplicity. It is a preferred way for writing inline code.

You can omit the parameter list in anonymous methods. Thus an anonymous method can be converted to delegates with a variety of signatures, which is not possible with lambda expressions.

Example:

// Demonstrate an anonymous method
using System;

// Declare a delegate type
delegate void ShowSum();

class AnonymousMethod
{
static void Main()
{
// The code for generating the sum is passed as an anonymous method
ShowSum oShowSum = delegate
{
// This is the block of code passed to the delegate
int iSum = 0;
for (int i = 0; i <= 5; i++)
{
iSum += i;
}
Console.WriteLine(iSum);
Console.ReadKey();
}; // Notice the semicolon
oShowSum();
}
}
 
Output: 15

Pass Arguments and Return a Value from an Anonymous Method

 

It is possible to pass one or more arguments to an anonymous method. To do so, follow the delegate keyword with a parenthesized parameter list. Then, pass the argument(s) to the delegate instance when it is called.

An anonymous method can also return a value. However, the type of the return value must be compatible with the return type specified by the delegate.

Example:


// Demonstrate an anonymous method that returns a value.
using System;
// This delegate returns a value. Notice that ShowSum now has a parameter.
delegate int ShowSum(int iEnd);
class AnonymousMethod
{
  static void Main()
  {
    int result;   
    // Here, the ending value for the count is passed to the anonymous method.
    // A summation of the count is returned.

    ShowSum oShowSum = delegate (int iEnd)
    {
       int iSum = 0;
       for(int i=0; i <= iEnd; i++)
       {
         Console.WriteLine(i);
         iSum += i;
       }
       return iSum;  // Return a value from an anonymous method
    };

    result = oShowSum(3);
    Console.WriteLine("Summation of 3 is " + result);
    Console.WriteLine();

    result = oShowSum(5);
    Console.WriteLine("Summation of 5 is " + result);

  }
}

Related Post: Delegates, Multicast Deletages (Multicasting)

Shallow Copy Vs Deep Copy

Shallow Copy


For instances of value types, the '=' assignment operator copies the state of the source object to the destination object. The copy is done byte-by-byte. Simple object copying by members is achievable through the method MemberwiseClone() inherited from System.Object. This is a protected method and the copying supplied by it is known as shallow copying (it copies the reference but not the referred object; thus the original object and its copy/clone refer to the same object).

Steps:

  • Create a new object 
  • Copy the non-static fields of the current object to the new object
  • For a value type field, copy is done byte-by-byte
  • For a reference type, shallow copy copies the reference but not the referred object

Example:

public class ShallowCopy
{
  public int iValue;
}

public class CloneMe
{
  public ShallowCopy oShallowCopy = new ShallowCopy();

  public CloneMe(int iNewValue)
  {
    oShallowCopy.iValue = iNewValue;
  }

  public object GetCopy()
  {
    return MemberwiseClone();
  }
}

In this case, the shallow copy obtained through GetCopy() will have a field that refers to the same object as the original.

The following code demonstrates using this class:

CloneMe oCloneMeSource = new CloneMe(10);
CloneMe oCloneMeTarget = (CloneMe)oCloneMeSource.GetCopy();
Console.Writeline("oCloneMeTarget - {0}", oCloneMeTarget.oShallowCopy.iValue);  // Output: oCloneMeTarget – 10
oCloneMeSource.oShallowCopy.iValue = 6;
Console.Writeline("oCloneMeTarget - {0}", oCloneMeTarget.oShallowCopy.iValue);  // Output: oCloneMeTarget – 6


Deep Copy


For instances of reference type, the '=' assignment operator copies the reference, and not the object. To copy the state of an object of reference type, we can use deep copying. Deep Copying is achieved by implementing the method Clone() which is the only method in System.ICloneable interface. This method returns a value of type System.Object.

Steps:
  • Create a new object
  • Copy the nonstatic fields of the current object to the new object
  • For a value type field, copy is done byte-by-byte
  • For a reference type, a new copy of the referred object is created

Example:

public class DeepCopy
{
  public int iValue;
}

public class CloneMe : ICloneable
{
  public DeepCopy oDeepCopy = new DeepCopy();

  public CloneMe(int iNewValue)
  {
     oDeepCopy.iValue = iNewValue; 
  }

  public object Clone()
  {
    CloneMe oCloneMe = new CloneMe(oDeepCopy.iValue);
    return oCloneMe;
  }
}

A new CloneMe object using the iValue field of the DeepCopy object contained in the original CloneMe object (oDeepCopy) is created here. This field is a value type, so no deep copying is necessary.

The following code demonstrates using this class:

CloneMe oCloneMeSource = new CloneMe(10);
CloneMe oCloneMeTarget = (CloneMe)oCloneMeSource.Clone();
Console.Writeline("oCloneMeTarget - {0}", oCloneMeTarget.oDeepCopy.iValue);  // Output: oCloneMeTarget – 10
oCloneMeSource.oDeepCopy.iValue = 6;
Console.Writeline("oCloneMeTarget - {0}", oCloneMeTarget.oDeepCopy.iValue);  // Output: oCloneMeTarget – 10

This time, the contained objects are independent.

Multicast Deletages (Multicasting)

Multicasting is the ability to create an invocation list, or chain, of methods that will be automatically called when a delegate is invoked.

Steps:
  • Instantiate a delegate
  • use the + or += operator to add methods to the chain
  • use the or –= operator to remove methods from the chain 
If the delegate returns a value, then the value returned by the last method in the list becomes the return value of the entire delegate invocation. 

Example:

// Multicasting Demo
using System;
// Declare a delegate type
delegate void ModifyString(ref string sTestString);

class MultiCastDemo
{
  // Replaces spaces with dollars
  static void ReplaceSpaces(ref string sTestString)
  { 
    sTestString = sTestString.Replace(' ', '$');
    Console.WriteLine("Replaced spaces with dollars.");
  }
  // Remove spaces
  static void RemoveSpaces(ref string sTestString)
  {
    string temp = "";
    int i;
    for(i=0; i < sTestString.Length; i++)
      if(sTestString[i] != ' ') temp += sTestString[i];
    sTestString = temp;
    Console.WriteLine("Removed spaces.");
  }
  // Reverse a string
  static void Reverse(ref string sTestString)
  {
    string temp = "";
    int i, j;
    for(j=0, i= sTestString.Length-1; i >= 0; i--, j++)
      temp += sTestString[i];
    sTestString = temp;
    Console.WriteLine("Reversed string.");
  }

  static void Main()
  {
    // Construct delegates
    ModifyString oModifyString;
    ModifyString oModifyStringReplaceSpaces = ReplaceSpaces;  // Method Group Conversion
    ModifyString oModifyStringRemoveSpaces = RemoveSpaces;  // Method Group Conversion
    ModifyString oModifyStringReverseString = Reverse;  // Method Group Conversion
    string sString = "This is a test for Multicast Delegates";
   
    // Set up multicast
    oModifyString = oModifyStringReplaceSpaces;
    oModifyString += oModifyStringReverseString;
   
    // Call multicast
    oModifyString(ref sString);
    Console.WriteLine("Resulting string: " + sString);
    Console.WriteLine();
   
    // Remove replace and add remove
    oModifyString -= oModifyStringReplaceSpaces;
    oModifyString += oModifyStringRemoveSpaces;
    sString = "This is a test."; // reset string
   
    // Call multicast
    oModifyString(ref sString);
    Console.WriteLine("Resulting string: " + sString);
    Console.WriteLine();
  }
}

Related Post: Delegates

Delegates


A delegate provides a way to encapsulate a method. It is an object that can refer to a method and can invoke the method to which it refers.

Delegates provide a built-in, language-supported mechanism for defining and executing callbacks. It provides an excellent mechanism to decouple the method being called from the actual caller. In fact, the caller of the delegate has no idea whether it is calling an instance method or a static method. To the caller, it is calling arbitrary code.

The principal advantage of a delegate is that the method that will be invoked by a delegate is not determined at compile time, but rather at runtime.

A delegate dynamically wires up a method caller to its target method. There are two aspects to a delegate: type and instance.

A delegate type defines a protocol to which the caller and target will conform, comprising a list of parameter types and a return type. A delegate instance is an object that refers to one or more target methods conforming to that protocol.

Delegate declarations look almost exactly like abstract method declarations, except for the delegate keyword. Ex:

public delegate double ComputeOutput( int iValueX, int iValueY );

When you instantiate an instance of a delegate, you must wire it up to a method to call when it is invoked. The method that you wire it up to could be either a static or an instance method that has a signature compatible with that of the delegate.

Thus, the parameter types and the return type must either match the delegate declaration or be implicitly convertible to the types in the delegate declaration.

using System;

public delegate double ComputeOutput( int iValueX, int iValueY ); // Delegate declaration

public class Computer
{
  public Computer ( double dFactor ) // Constructor   
  {
    this.dFactor = dFactor;
  }
  public double ComputeInstance( int iValueX, int iValueY ) // instance method
  {
    double dResult = (iValueX + iValueY) * dFactor;
    Console.WriteLine( "Instance Results: {0}", dResult );
    return dResult;
  }
  public static double ComputeStatic( int iValueX, int iValueY ) // static method
  {
    double dResult = (iValueX + iValueY) * 0.5;
    Console.WriteLine( "Static Result: {0}", dResult );
    return dResult;
  }
  private double dFactor;
}

public class MyComputer
{
  static void Main()
  {
    Computer oComputer1 = new Computer( 0.69 );
    Computer oComputer2 = new Computer( 0.76 );
    ComputeOutput delegate1 = new ComputeOutput (oComputer1.ComputeInstance );
    ComputeOutput delegate2 = new ComputeOutput (oComputer2.ComputeInstance );
    // points to a static method - use method group conversion
    ComputeOutput delegate3 = Computer.ComputeStatic; 
    double dTotal = delegate1( 7, 8 ) + delegate2( 9, 2 ) + delegate3( 4, 3 );
    Console.WriteLine( "Output: {0}", dTotal );
  }
}

Method Group Conversion allows you to simply assign the name of a method to a delegate, without using new or explicitly invoking the delegate’s constructor. 

Computer.StaticCompute is actually called a method group because the method could be overloaded and this name could refer to a group of methods. In this case, the method group Computer.StaticCompute has one method in it.
 
C# allows you to directly assign a delegate from a method group. When you create the delegate instances via new, you pass the method group in the constructor.

Introduction to Delegates



Related Post: Multicast Delegates (Multicasting)

List ASP.NET Page Life Cycle events

Page Event
Controls Initialized
Is ViewState Enabled
 When is this Event Raised
Logic

PreInit

No No After the start stage is complete and before the initialization stage begins This event can be used for the following:
1) Check the IsPostBack property. The IsCallback and IsCrossPagePostBack properties are also set at this time.
2) Create or re-create dynamic controls.
3) Set a master page dynamically.
4) Set the Theme property dynamically.
5) Read or set profile property values.
Note: If the request is a postback, the values of the controls have not yet been restored from view state.

Init

Not guaranteed No After all controls have been initialized and any skin settings have been applied. The Init event of individual controls occurs before the Init event of the page. This event can be used to read or initialize control properties.

InitComplete

Not guaranteed Yes At the end of the page’s initialization stage.
Only one operation takes place between the Init and InitComplete events: tracking of view state changes is turned on. View state tracking enables controls to persist any values that are programmatically added to the ViewState collection.
This event can be used to make changes to view state that you want to make sure are persisted after the next postback.

LoadViewState

Not guaranteed Yes This event happens only at postbacks
The Viewstate which has been saved in the __VIEWSTATE during the previous page visit (via the SaveViewState event) is loaded and then populated into the control hierarchy.

LoadPostbackdata

Not guaranteed Yes This event happens only at postbacks
During this event, the posted form data is loaded into the appropriate controls.

PreLoad

Yes Yes After the page loads view state for itself and all controls, and after it processes postback data that is included with the Request instance.

Load

Yes Yes
The Page object calls the OnLoad method on the Page object, and then recursively does the same for each child control until the page and all controls are loaded. The Load event of individual controls occurs after the Load event of the page.
The OnLoad event can be used to set control properties and database connections.

Control events

Yes Yes Raised at the end of the event-handling stage.
These events can be used to handle specific control events, such as a Button control’s Click event or a TextBox control’s TextChanged event.
Note: In a postback request, if the page contains validator controls, check the IsValid property of the Page and of individual validation controls before performing any processing.

LoadComplete

Yes Yes Raised after the Page object has created all controls that are required in order to render the page, including child controls of composite controls.This event can be used for tasks that require that all other controls on the page be loaded.

PreRender

Yes Yes

The Page object raises the PreRender event on the Page object, and then recursively does the same for each child control. The PreRender event of individual controls occurs after the PreRender event of the page.

 The event can be used to make final changes to the contents of the page or its controls before the rendering stage begins.

PreRenderComplete

Yes Yes
Raised after each data bound control whose DataSourceID property is set calls its DataBind method.

SaveStateComplete

Yes Yes
Raised after view state and control state have been saved for the page and for all controls.
Any changes to the page or controls at this point affect rendering, but the changes will not be retrieved on the next postback.

Render

Yes Yes This is not an event; instead, at this stage of processing, the Page object calls this method on each control. All ASP.NET Web server controls have a Render method that writes out the control’s markup to send to the browser.


If you create a custom control, you typically override this method to output the control’s markup. However, if your custom control incorporates only standard ASP.NET Web server controls and no custom markup, you do not need to override the Render method.
We do not need to explicitly render the control in code because a user control automatically incorporates rendering.

Unload

Yes Yes Raised for each control and then for the page.
This event can be used to do final cleanup for specific controls, such as closing control-specific database connections.
Note: During the unload stage, the page and its controls have been rendered, so you cannot make further changes to the response stream. If you attempt to call a method such as the Response.Write method, the page will throw an exception.