Saturday, 24 August 2013

IXmlSerializable – Control XML Serialization

Sometimes we are in hard need to control the xml serialization. One of these needs could be to reduce the serialized data, so that less data will travel over wire and hence we will get the improved data transfer speed.

To control it, we can use the IXmlSerializable interface. This interface contains three functions

  1. XmlSchema GetSchema()
  2. void ReadXml(XmlReader reader)
  3. void WriteXml(XmlWriter writer)

In these functions, we can control the serialization with the help of XMLReader and XMLWriter. IXmlSerializable interface is recognized by the both XmlSerializer and Data Contract Serializer; and hence it can be used used by WCF and ASMX Web Services.

Lets have a look into the code - 

Code

using System;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XMLSerialization
{
internal class Program
{
private static void Main(string[] args)
{
Person[] p = new Person[3];
p[0] = new Person() { Name = "Sanjay", Age = 30 };
p[1] = new Person() { Name = "Sanjay Legha", Age = 0 };
p[2] = new Person() { Age = 30 };

//Person p = new Person() { Name = "Sanjay", Age = 50 };

string filePath = @"D:\Sanjay\TempCode\XMLSerialization\XMLSerialization\bin\Debug\Serialized.xml";
using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
x.Serialize(fs, p);
}

using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
object obj = x.Deserialize(fs);
}

Console.Write("Done");
Console.Read();
}
}

public class Person : IXmlSerializable
{
public Person()
{
this.Name = string.Empty;
this.Age = 0;
}

[XmlElement(IsNullable = false)]
public string Name { get; set; }

[XmlElement()]
public int Age { get; set; }

public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader reader)
{
if (reader.NodeType == XmlNodeType.Element)
{
XElement el = XNode.ReadFrom(reader) as XElement;

foreach (var item in el.Nodes())
{
if (item is XElement)
{
XElement node = item as XElement;
switch (node.Name.LocalName)
{
case "Name":
this.Name = node.Value;
break;

case "Age":
this.Age = Convert.ToInt32(node.Value);
break;
}
}
}
}
}

public void WriteXml(XmlWriter writer)
{
if (!string.IsNullOrWhiteSpace(Name))
writer.WriteElementString("Name", Name);

if (Age != 0)
writer.WriteElementString("Age", Age.ToString());
}
}
}

Output

<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Person>
    <Name>Sanjay</Name>
    <Age>30</Age>
  </Person>
  <Person>
    <Name>Sanjay Legha</Name>
  </Person>
  <Person>
    <Age>30</Age>
  </Person>
</ArrayOfPerson>

Generic Serialize Deserialize - XmlSerializer

 

A generic Xml Serializer De-Serializer code snap

public class SerializeDeserialize
{
    public static void SerializeData<T>(string filePath, T data)
    {
        using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.CreateNew))
        {
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(data.GetType());
            x.Serialize(fs, data);
        }
    }

    public static T DeSerializeData<T>(string filePath)
    {
        T data;
        using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
        {
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
            object obj = x.Deserialize(fs);
            data = (T)obj;
        }

        return data;
    }
}

Saturday, 25 February 2012

Programmatically Compile And Use Code Using C#

 

Introduction

It is always better if you could create all your required classes in your project. But, sometimes it becomes very crucial if you could create a class for the specific situation at runtime or if you could change the existing one.

To overcome this situation, .Net Framework exposes some class that allow us to programmatically access the C# language compiler.

In this post I am demonstrating how to create an entity class and its collection class through a windows application, and passing the collection class object to the DataGridView as DataSource.

Note: I am assuming you have the basic knowledge of reflection.

How To

Setup the project and form

In this example I am using the basic windows forms application. You can follow the following steps to setup this application -

  • Create a Windows Forms Application. It will create a form with name Form1.
  • Add a button on Form1 and name it btnCompile.
  • Add a DataGridView. Here I am using its default name dataGridView1.
  • Double click on the btnCompile to generate the event handler.

 

Implement the compiler

After adding code in event handler, your code should look like -

private void btnCompile_Click(object sender, EventArgs e)
{
    // code string to compile
    string code =
@"class EntityCollection : System.Collections.Generic.List<Entity> {}

class Entity
{
    public string Name { get; set; }

    public int Age { get; set; }
}";

    // RETRIEVING COMPILER INTERFACE
    CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    ICodeCompiler codeCompiler = codeProvider.CreateCompiler();


    // PREPARING COMPILER PARAMETERS
    CompilerParameters compilerParameters = new CompilerParameters();
    compilerParameters.GenerateInMemory = true;
    compilerParameters.TreatWarningsAsErrors = false;
    compilerParameters.WarningLevel = 4;
    compilerParameters.ReferencedAssemblies.Add("System.dll");

    // COMPILING CODE
    CompilerResults results = codeCompiler.CompileAssemblyFromSource(compilerParameters, code);

    if (results.Errors.Count > 0)
    {
        StringBuilder sbExceptions = new StringBuilder();

        foreach (CompilerError CompErr in results.Errors)
        {
            sbExceptions.AppendLine(
                            "Line number " + CompErr.Line +
                            ", Error Number: " + CompErr.ErrorNumber +
                            ", '" + CompErr.ErrorText + ";" +
                            Environment.NewLine + Environment.NewLine);
        }

        MessageBox.Show("Exception raised while compiling your code: \n\n" + sbExceptions.ToString());
    }
    else
    {
        // GETTING COMPILED ASSEMBLY
        Assembly assembly = results.CompiledAssembly;

        // RETRIEVING COLLECTION CLASS FROM COMPILED ASSEMBLY.
        Type type = assembly.GetType("EntityCollection");

        // CREATING INSTANCE OF COLLECTION CLASS
        IList list = (IList)Activator.CreateInstance(type);

        // RETRIEVING ENTITY CLASS FROM COMPILED ASSEMBLY.
        Type eType = assembly.GetType("Entity");
        object obj = Activator.CreateInstance(eType);

        // ASSIGNING VALUES TO THE ENTITY CLASS OBJECT.
        eType.GetProperty("Name").SetValue(obj, "Sanjay", null);
        eType.GetProperty("Age").SetValue(obj, 30, null);

        // ADDING CLASS TO COLLECTION OBJECT
        list.Add(obj);

        // ASSIGNED LIST TO GRID VIEW AS DATA SOURCE
        dataGridView1.DataSource = list;
    }
}

About code

.NET Framework provides the ICodeCompiler compiler execution interface.The CSharpCodeProvider class implements this interface and provides access to the C# code compiler. The following code creates an instance of CSharpCodeProvider and initializes ICodeCompiler interface object.

CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler codeCompiler = codeProvider.CreateCompiler();

Now you have the compiler interface which can be used to compile your source code. You need to pass parameters to the compiler by using the CompilerParameters class.

CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.GenerateInMemory = true;
compilerParameters.TreatWarningsAsErrors = false;
compilerParameters.WarningLevel = 4;
compilerParameters.ReferencedAssemblies.Add("System.dll");

CompilerResults results = codeCompiler.CompileAssemblyFromSource(compilerParameters, code);

CompilerParameters object is used to pass parameters to tell the compiler that you want to generate a class library in memory which can be used further in the code. To compile code you will use function CompileAssemblyFromSource. CompileAssemblyFromSource method takes the compilerParameters object and the source code, which is a string.

Once the code is compiled, you can check to see if there were any compilation errors. You can use the return value from CompileAssemblyFromSource method, which is a CompilerResults object. This object contains an errors collection, which contains any errors that occurred during the compilation process.

Below code collects all the errors in the string builder class which is for demonstration only which you can user for your purpose -

if (results.Errors.Count > 0)
{
    StringBuilder sbExceptions = new StringBuilder();

    foreach (CompilerError CompErr in results.Errors)
    {
        sbExceptions.AppendLine(
                        "Line number " + CompErr.Line +
                        ", Error Number: " + CompErr.ErrorNumber +
                        ", '" + CompErr.ErrorText + ";" +
                        Environment.NewLine + Environment.NewLine);
    }

    MessageBox.Show("Exception raised while compiling your code: \n\n" + sbExceptions.ToString());
}

Once the assembly is generated without any error you can use it in your code. I have used it to generate a list of items and binded this list to the grid view as its data source -

else
    {
        // GETTING COMPILED ASSEMBLY
        Assembly assembly = results.CompiledAssembly;

        // RETRIEVING COLLECTION CLASS FROM COMPILED ASSEMBLY.
        Type type = assembly.GetType("EntityCollection");

        // CREATING INSTANCE OF COLLECTION CLASS
        IList list = (IList)Activator.CreateInstance(type);

        // RETRIEVING ENTITY CLASS FROM COMPILED ASSEMBLY.
        Type eType = assembly.GetType("Entity");
        object obj = Activator.CreateInstance(eType);

        // ASSIGNING VALUES TO THE ENTITY CLASS OBJECT.
        eType.GetProperty("Name").SetValue(obj, "Sanjay", null);
        eType.GetProperty("Age").SetValue(obj, 30, null);

        // ADDING CLASS TO COLLECTION OBJECT
        list.Add(obj);

        // ASSIGNED LIST TO GRID VIEW AS DATA SOURCE
        dataGridView1.DataSource = list;
    }


Once the compilation successes, build assembly can be retrieved from CompileAssemblyFromSource method’s return value which contains CompiledAssembly property.

Now you have the compiled assembly. You can play with it as you wish.

Sunday, 12 February 2012

Extension Methods In Dot Net, C#

Sometimes we are in need to extend any class but often it is just not possible to use inheritance if you are working with a value type, a sealed class, or an interface. C# 3 introduces the idea of extension methods.

Extension methods allows an existing type to be extended with new methods without altering the definition of the original type.

SYNTAX

You cannot use any method as the extension method – it has to have the following characteristics:

  • It has to be in a non-nested, non-generic static class and therefore has to be a static method.
  • It has to have at least one parameter where the type of the first parameter will be the type that is extends.
  • The first parameter has to be prefixed with this keyword.

In final words, an extension method is a static method of a static class, where the this modifier is applied to the first parameter. The type of the first parameter will be the type that is extended.

For example:

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' },
               StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }  
}

Syntax Explanation

MyExtensions class is a static class and WordCount is a static method of static class. this keyword tells that this is an extension method. Type of first parameter tells it is extending string class.

Usage

The WordCounts extension method can be called as it was an instance method of a string class, as follows:

Console.WriteLine ("Hello Extension Methods".WordCount());

or

string s = "Hello Extension Methods";
int i = s.WordCount();

Note: Extension methods are only in scope when you explicitly import the namespace into your source code with a using directive.

In your code you invoke the extension method with instance method syntax. However, the intermediate language (IL) generated by the compiler translates your code into a call on the static method. Therefore, the principle of encapsulation is not really being violated. In fact, extension methods cannot access private variables in the type they are extending.

The above function’s translation will be as follows:

Console.WriteLine (MyExtensions.WordCount("Hello Extension Methods"));

Extending Interfaces

LINQ has already extended lots of interfaces like, IEnumerable, IEnumerable<T>, IList, IList<T> etc.

A simple syntax of how to extend the interface is:

public static T First<T> (this IEnumerable<T> sequence)
{
    foreach (T element in sequence)
        return element;

    throw new InvalidOperationException ("No elements found!");
}
...
Console.WriteLine ((new int[]{23,453,345}).First());

Extension Method Chaining

Extension methods, like instance methods, provide a tidy way to chain functions. Consider the following two functions:

IList<string> strings = new List<string>();
strings.Add("Hello");
strings.Add("Extension");
strings.Add("Methods");

strings.First().WordCount();

Ambiguity and Resolution

As mentioned above, Extension Methods are only in scope when you explicitly import the namespace into your source code with a using directive. Consider the extension method WordCount, the following application must import ExtensionMethods, in order to avoid a compile-time error:

namespace TestApp
{
    using ExtensionMethods; // importing namespace
    class Test
    {
        static void Main()
        {
            Console.WriteLine ("Hello Extension Methods".WordCount());
        }
    }
}

Extension methods v.s. instance methods

As per the standard preference rule, any compatible instance method will always take precedence over the extension method. In the following example, Test’s Foo method will always take precedence even when called with an argument x of type int:

class Test
{
    public void Foo (object x) { } // This method always wins
}
static class Extensions
{
    public static void Foo (this Test t, int x) { }
}

The only way to call the extension method in this case is via normal static syntax-

Extensions.Foo(...).

Extension methods versus extension methods

If two extension methods have the same signature then the method must be called as an ordinary static method to resolve ambiguity.

If one extension method has more specific arguments, then the more specific method takes precedence. To illustrate, consider the following two classes:

static class StringExtensions
{
    public static int WordCount (this string s) {...}
}
static class ObjectExtensions
{
    public static int WordCount (this object s) {...}
}

The following code calls StringExtensions’s WordCount method:

int wordCount = "Hello Extension Methods".WordCount();

To call ObjectExtensions’s WordCount method, we must specify it explicitly:

int wordCount = (ObjectExtensions.WordCount ("Hello Extension Methods"));

Delegates VS Interfaces

Delegates and interfaces are similar in that they enable the separation of specification and implementation. Multiple independent authors can produce implementations that are compatible with an interface specification. Similarly, a delegate specifies the signature of a method, and authors can write methods that are compatible with the delegate specification. When should you use interfaces, and when should you use delegates?

Delegates are useful when:

  • A single method is being called.
  • A class may want to have multiple implementations of the method specification.
  • It is desirable to allow using a static method to implement the specification.
  • An event-like design pattern is desired (for more information, see the Introduction To Events post).
  • The caller has no need to know or obtain the object that the method is defined on.
  • The provider of the implementation wants to "hand out" the implementation of the
  • specification to only a few select components.
  • Easy composition is desired.

Interfaces are useful when:

  • The specification defines a set of related methods that will be called.
  • A class typically implements the specification only once.
  • The caller of the interface wants to cast to or from the interface type to obtain other interfaces or classes.

Saturday, 11 February 2012

Introduction to C# Events

An event is a member that enables an object or class to provide notifications. Clients can attach executable code for events by supplying event handlers. Events work on broadcaster / subscriber model where one object is broadcasting events and other attached objects are subscribing with those events.

Events are declared using event-declarations:

event-declaration:
      event-modifier
event type variable-declaration;

event-modifiers:
    new
    public
    protected
    internal
    private
    static
    virtual
    sealed
    override
    abstract
    extern

An event-declaration may include a set of attributes and access modifiers, the new, static, virtual, override, sealed, abstract, and extern modifiers.

Event declarations are subject to the same rules as method declarations with regard to valid combinations of modifiers.

The type of an event declaration must be a delegate-type, and that delegate-type must be at least as accessible as the event itself.

An event declaration may include event-accessor-declarations. However, if it does not, for non-extern, non-abstract events, the compiler supplies them automatically; for extern events, the accessors are provided externally.

An event declaration that omits event-accessor-declarations defines one or more events—one for each of the variable-declarators. The attributes and modifiers apply to all of the members declared by such an event-declaration.

It is a compile-time error for an event-declaration to include both the abstract modifier and brace-delimited event-accessor-declarations.

When an event declaration includes an extern modifier, the event is said to be an external event. Because an external event declaration provides no actual implementation, it is an error for it to include both the extern modifier and event-accessor-declarations.

An event can be used as the left-hand operand of the += and -= operators. These operators are used, respectively, to attach event handlers to or to remove event handlers from an event, and the access modifiers of the event control the contexts in which such operations are permitted.

Since += and -= are the only operations that are permitted on an event outside the type that declares the event, external code can add and remove handlers for an event, but cannot in any other way obtain or modify the underlying list of event handlers.

In an operation of the form x += y or x -= y, when x is an event and the reference takes place outside the type that contains the declaration of x, the result of the operation has type void (as opposed to having the type of x, with the value of x after the assignment). This rule prohibits external code from indirectly examining the underlying delegate of an event.

The following example shows how event handlers are attached to instances of the Button class:

public delegate void EventHandler(object sender, EventArgs e);
public class Button: Control
{
    public event EventHandler Click;
}
public class LoginDialog: Form
{
    Button OkButton;
    Button CancelButton;
    public LoginDialog()
   
{
        OkButton = new Button(...);
        OkButton.Click += new EventHandler(OkButtonClick);
        CancelButton = new Button(...);
        CancelButton.Click += new EventHandler(CancelButtonClick);
    }
    void OkButtonClick(object sender, EventArgs e)
   
{
        // Handle OkButton.Click event
    }
    void CancelButtonClick(object sender, EventArgs e)
    {
        // Handle CancelButton.Click event
    }
}

Here, the LoginDialog instance constructor creates two Button instances and attaches event handlers to the Click events.

Field-like events

Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be used in this way, an event must not be abstract or extern, and must not explicitly include event-accessor-declarations. Such an event can be used in any context that permits a field. The field contains a delegate which refers to the list of event handlers that have been added to the event. If no event handlers have been added, the field contains null.

In the example

public delegate void EventHandler(object sender, EventArgs e);
public class Button: Control
{
    public event EventHandler Click;
    protected void OnClick(EventArgs e)
    {
        if (Click != null) Click(this, e);
    }
    public void Reset()
    {
        Click = null;
    }
}

Click is used as a field within the Button class. As the example demonstrates, the field can be examined, modified, and used in delegate invocation expressions. The OnClick method in the Button class “raises” the Click event. The notion of raising an event is precisely equivalent to invoking the delegate represented by the event—thus, there are no special language constructs for raising events. Note that the delegate invocation is preceded by a check that ensures the delegate is non-null.

Outside the declaration of the Button class, the Click member can only be used on the left-hand side of the += and –= operators, as in

b.Click += new EventHandler(…);

which appends a delegate to the invocation list of the Click event, and

b.Click –= new EventHandler(…);

which removes a delegate from the invocation list of the Click event.

When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. In order to be thread-safe, the addition or removal operations are done while holding the lock on the containing object for an instance event, or the type object for a static event.

Thus, an instance event declaration of the form:

class X
{
    public event D Ev;
}

could be compiled to something equivalent to:

class X
{
    private D __Ev;  // field to hold the delegate
    public event D Ev {
        add {
            lock(this) { __Ev = __Ev + value; }
        }
        remove {
            lock(this) { __Ev = __Ev - value; }
        }
    }
}

Within the class X, references to Ev are compiled to reference the hidden field __Ev instead. The name “__Ev” is arbitrary; the hidden field could have any name or no name at all.

Similarly, a static event declaration of the form:

class X
{
    public static event D Ev;
}

could be compiled to something equivalent to:

class X
{
    private static D __Ev;  // field to hold the delegate
    public static event D Ev {
        add {
            lock(typeof(X)) { __Ev = __Ev + value; }
        }
        remove {
            lock(typeof(X)) { __Ev = __Ev - value; }
        }
    }
}

Event accessors

Event declarations typically omit event-accessor-declarations, as in the Button example above. One situation for doing so involves the case in which the storage cost of one field per event is not acceptable. In such cases, a class can include event-accessor-declarations and use a private mechanism for storing the list of event handlers.

The event-accessor-declarations of an event specify the executable statements associated with adding and removing event handlers.

The accessor declarations consist of an add-accessor-declaration and a remove-accessor-declaration. Each accessor declaration consists of the token add or remove followed by a block. The block associated with an add-accessor-declaration specifies the statements to execute when an event handler is added, and the block associated with a remove-accessor-declaration specifies the statements to execute when an event handler is removed.

Each add-accessor-declaration and remove-accessor-declaration corresponds to a method with a single value parameter of the event type and a void return type. The implicit parameter of an event accessor is named value. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is += then the add accessor is used, and if the assignment operator is -= then the remove accessor is used. In either case, the right-hand operand of the assignment operator is used as the argument to the event accessor. The block of an add-accessor-declaration or a remove-accessor-declaration must conform to the rules for void methods. In particular, return statements in such a block are not permitted to specify an expression.

Since an event accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declared in an event accessor to have that name.

In the example

class Control: Component
{
    // Unique keys for events
    static readonly object mouseDownEventKey = new object();
    static readonly object mouseUpEventKey = new object();
    // Return event handler associated with key
    protected Delegate GetEventHandler(object key) {...}
    // Add event handler associated with key
    protected void AddEventHandler(object key, Delegate handler) {...}
    // Remove event handler associated with key
    protected void RemoveEventHandler(object key, Delegate handler) {...}
    // MouseDown event
    public event MouseEventHandler MouseDown {
        add { AddEventHandler(mouseDownEventKey, value); }
        remove { RemoveEventHandler(mouseDownEventKey, value); }
    }
    // MouseUp event
    public event MouseEventHandler MouseUp {
        add { AddEventHandler(mouseUpEventKey, value); }
        remove { RemoveEventHandler(mouseUpEventKey, value); }
    }
    // Invoke the MouseUp event
    protected void OnMouseUp(MouseEventArgs args) {
        MouseEventHandler handler;
        handler = (MouseEventHandler)GetEventHandler(mouseUpEventKey);
        if (handler != null)
            handler(this, args);
    }
}

the Control class implements an internal storage mechanism for events. The AddEventHandler method associates a delegate value with a key, the GetEventHandler method returns the delegate currently associated with a key, and the RemoveEventHandler method removes a delegate as an event handler for the specified event. Presumably, the underlying storage mechanism is designed such that there is no cost for associating a null delegate value with a key, and thus unhandled events consume no storage.

Static and instance events

When an event declaration includes a static modifier, the event is said to be a static event. When no static modifier is present, the event is said to be an instance event.

A static event is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static event.

An instance event is associated with a given instance of a class, and this instance can be accessed as this in the accessors of that event.

When an event is referenced in a member-access of the form E.M, if M is a static event, E must denote a type containing M, and if M is an instance event, E must denote an instance of a type containing M.

Virtual, sealed, override, and abstract accessors

A virtual event declaration specifies that the accessors of that event are virtual. The virtual modifier applies to both accessors of an event.

An abstract event declaration specifies that the accessors of the event are virtual, but does not provide an actual implementation of the accessors. Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the event. Because an abstract event declaration provides no actual implementation, it cannot provide brace-delimited event-accessor-declarations.

An event declaration that includes both the abstract and override modifiers specifies that the event is abstract and overrides a base event. The accessors of such an event are also abstract.

Abstract event declarations are only permitted in abstract classes.

The accessors of an inherited virtual event can be overridden in a derived class by including an event declaration that specifies an override modifier. This is known as an overriding event declaration. An overriding event declaration does not declare a new event. Instead, it simply specializes the implementations of the accessors of an existing virtual event.

An overriding event declaration must specify the exact same accessibility modifiers, type, and name as the overridden event.

An overriding event declaration may include the sealed modifier. Use of this modifier prevents a derived class from further overriding the event. The accessors of a sealed event are also sealed.

It is a compile-time error for an overriding event declaration to include a new modifier.

Introduction to C# Delegates

Delegates enable scenarios that other languages such as C++, Pascal, and Modula have addressed with function pointers. Unlike C++ function pointers, however, delegates are fully object oriented, and unlike C++ pointers to member functions, delegates encapsulate both an object instance and a method.

A delegate declaration defines a class that is derived from the class System.Delegate. A delegate instance encapsulates an invocation list, which is a list of one or more methods, each of which is referred to as a callable entity. For instance methods, a callable entity consists of an instance and a method on that instance. For static methods, a callable entity consists of just a method. Invoking a delegate instance with an appropriate set of arguments causes each of the delegate’s callable entities to be invoked with the given set of arguments.

An interesting and useful property of a delegate instance is that it does not know or care about the classes of the methods it encapsulates; all that matters is that those methods be compatible with the delegate’s type. This makes delegates perfectly suited for “anonymous” invocation.

Delegate declarations

A delegate-declaration is a type-declaration that declares a new delegate type.

delegate-declaration:
attributes delegate return-type(formal-parameter-list);

delegate-modifier:
new
public
protected
internal

private

It is a compile-time error for the same modifier to appear multiple times in a delegate declaration.

The new modifier is only permitted on delegates declared within another type, in which case it specifies that such a delegate hides an inherited member by the same name.

The optional formal-parameter-list specifies the parameters of the delegate, and return-type indicates the return type of the delegate.

The return type of a delegate type must be either void, or output-safe.

All the formal parameter types of a delegate type must be input-safe. Additionally, any out or ref parameter types must also be output-safe. Note that even out parameters are required to be input-safe, due to a limitation of the underlying execution platform.

Delegate types in C# are name equivalent, not structurally equivalent. Specifically, two different delegate types that have the same parameter lists and return type are considered different delegate types. However, instances of two distinct but structurally equivalent delegate types may compare as equal.

For example:

delegate int D1(int i, double d);

class A
{
public static int M1(int a, double b) {...}
}

class B
{
delegate int D2(int c, double d);
public static int M1(int f, double g) {...}
public static void M2(int k, double l) {...}
public static int M3(int g) {...}
public static void M4(int g) {...}
}

The delegate types D1 and D2 are both compatible with the methods A.M1 and B.M1, since they have the same return type and parameter list; however, these delegate types are two different types, so they are not interchangeable. The delegate types D1 and D2 are incompatible with the methods B.M2, B.M3, and B.M4, since they have different return types or parameter lists.


Like other generic type declarations, type arguments must be given to create a constructed delegate type. The parameter types and return type of a constructed delegate type are created by substituting, for each type parameter in the delegate declaration, the corresponding type argument of the constructed delegate type. The resulting return type and parameter types are used in determining what methods are compatible with a constructed delegate type. For example:

delegate bool Predicate(T value);

class X
{
static bool F(int i) {...}
static bool G(string s) {...}
}

The delegate type Predicate<int> is compatible with the method X.F and the delegate type Predicate<string> is compatible with the method X.G.


The only way to declare a delegate type is via a delegate-declaration. A delegate type is a class type that is derived from System.Delegate. Delegate types are implicitly sealed, so it is not permissible to derive any type from a delegate type. It is also not permissible to derive a non-delegate class type from System.Delegate. Note that System.Delegate is not itself a delegate type; it is a class type from which all delegate types are derived.


C# provides special syntax for delegate instantiation and invocation. Except for instantiation, any operation that can be applied to a class or class instance can also be applied to a delegate class or instance, respectively. In particular, it is possible to access members of the System.Delegate type via the usual member access syntax.


The set of methods encapsulated by a delegate instance is called an invocation list. When a delegate instance is created from a single method, it encapsulates that method, and its invocation list contains only one entry. However, when two non-null delegate instances are combined, their invocation lists are concatenated—in the order left operand then right operand—to form a new invocation list, which contains two or more entries.


Delegates are combined using the binary + and += operators. A delegate can be removed from a combination of delegates, using the binary - and -= operators. Delegates can be compared for equality.


The following example shows the instantiation of a number of delegates, and their corresponding invocation lists:

delegate void D(int x);

class C
{
public static void M1(int i) {...}
public static void M2(int i) {...}
}

class Test
{
static void Main ()
{
D cd1 = new D(C.M1); // M1
D cd2 = new D(C.M2); // M2
D cd3 = cd1 + cd2; // M1 + M2
D cd4 = cd3 + cd1; // M1 + M2 + M1
D cd5 = cd4 + cd3; // M1 + M2 + M1 + M1 + M2
}
}

When cd1 and cd2 are instantiated, they each encapsulate one method. When cd3 is instantiated, it has an invocation list of two methods, M1 and M2, in that order. cd4’s invocation list contains M1, M2, and M1, in that order. Finally, cd5’s invocation list contains M1, M2, M1, M1, and M2, in that order. For more examples of combining (as well as removing) delegates.


Delegate compatibility


A method or delegate M is compatible with a delegate type D if all of the following are true:




  • D and M have the same number of parameters, and each parameter in D has the same ref or out modifiers as the corresponding parameter in M.


  • For each value parameter (a parameter with no ref or out modifier), an identity conversion or implicit reference conversion exists from the parameter type in D to the corresponding parameter type in M.


  • For each ref or out parameter, the parameter type in D is the same as the parameter type in M.


  • An identity or implicit reference conversion exists from the return type of M to the return type of D.

Delegate instantiation


An instance of a delegate is created by a delegate-creation-expression or a conversion to a delegate type. The newly created delegate instance then refers to either:




  • The static method referenced in the delegate-creation-expression, or


  • The target object (which cannot be null) and instance method referenced in the delegate-creation-expression, or


  • Another delegate.

For example:

delegate void D(int x);

class C
{
public static void M1(int i) {...}
public void M2(int i) {...}
}

class Test
{
static void Main ()
{
D cd1 = new D(C.M1); // static method
C t = new C();
D cd2 = new D(t.M2); // instance method
D cd3 = new D(cd2); // another delegate
}
}


Once instantiated, delegate instances always refer to the same target object and method. Remember, when two delegates are combined, or one is removed from another, a new delegate results with its own invocation list; the invocation lists of the delegates combined or removed remain unchanged.


Delegate invocation


C# provides special syntax for invoking a delegate. When a non-null delegate instance whose invocation list contains one entry is invoked, it invokes the one method with the same arguments it was given, and returns the same value as the referred to method. If an exception occurs during the invocation of such a delegate, and that exception is not caught within the method that was invoked, the search for an exception catch clause continues in the method that called the delegate, as if that method had directly called the method to which that delegate referred.


Invocation of a delegate instance whose invocation list contains multiple entries proceeds by invoking each of the methods in the invocation list, synchronously, in order. Each method so called is passed the same set of arguments as was given to the delegate instance. If such a delegate invocation includes reference parameters, each method invocation will occur with a reference to the same variable; changes to that variable by one method in the invocation list will be visible to methods further down the invocation list. If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.


If an exception occurs during processing of the invocation of such a delegate, and that exception is not caught within the method that was invoked, the search for an exception catch clause continues in the method that called the delegate, and any methods further down the invocation list are not invoked.


Attempting to invoke a delegate instance whose value is null results in an exception of type System.NullReferenceException.


The following example shows how to instantiate, combine, remove, and invoke delegates:

using System;

delegate void D(int x);

class C
{
public static void M1(int i)
{
Console.WriteLine("C.M1: " + i);
}

public static void M2(int i)
{
Console.WriteLine("C.M2: " + i);
}

public void M3(int i)
{
Console.WriteLine("C.M3: " + i);
}
}

class Test
{
static void Main ()
{
D cd1 = new D(C.M1);
cd1(-1); // call M1

D cd2 = new D(C.M2);
cd2(-2); // call M2

D cd3 = cd1 + cd2;
cd3(10); // call M1 then M2

cd3 += cd1;
cd3(20); // call M1, M2, then M1

C c = new C();
D cd4 = new D(c.M3);
cd3 += cd4;
cd3(30); // call M1, M2, M1, then M3

cd3 -= cd1; // remove last M1
cd3(40); // call M1, M2, then M3

cd3 -= cd4;
cd3(50); // call M1 then M2

cd3 -= cd2;
cd3(60); // call M1

cd3 -= cd2; // impossible removal is benign
cd3(60); // call M1

cd3 -= cd1; // invocation list is empty so cd3 is null
// cd3(70); // System.NullReferenceException thrown

cd3 -= cd1; // impossible removal is benign
}
}

As shown in the statement cd3 += cd1;, a delegate can be present in an invocation list multiple times. In this case, it is simply invoked once per occurrence. In an invocation list such as this, when that delegate is removed, the last occurrence in the invocation list is the one actually removed.


Immediately prior to the execution of the final statement, cd3 -= cd1;, the delegate cd3 refers to an empty invocation list. Attempting to remove a delegate from an empty list (or to remove a non-existent delegate from a non-empty list) is not an error.


The output produced is:


C.M1: -1
C.M2: -2
C.M1: 10
C.M2: 10
C.M1: 20
C.M2: 20
C.M1: 20
C.M1: 30
C.M2: 30
C.M1: 30
C.M3: 30
C.M1: 40
C.M2: 40
C.M3: 40
C.M1: 50
C.M2: 50
C.M1: 60
C.M1: 60