Category Archives: Delegates

Generic types (part 2, basics, advanced)

We have looked into generic classes in part 1 https://csharphardcoreprogramming.wordpress.com/2014/01/01/generic-types-part-1-basics-advanced/.
On the following day I used a generic method when explaining reflection https://csharphardcoreprogramming.wordpress.com/2014/01/02/reflection-basics-advanced/.

Let’s look at generic delegates more closely. They look neat and make code, as the name says, more generic.

delegate T Calc<T>(T a, T b);
private static int Add(int a, int b) { return a + b; }
private static double Multiply(double a, double b) { return a * b; }

public static void Generics8() {
    Calc<double> lProduct = Multiply;
    Calc<int> lSum = Add;

    Console.WriteLine("Product:" + lProduct(5.0, 2.0));
    Console.WriteLine("Sum:" + lSum(5, 2));
    Console.ReadKey();
} //

We can also use constraints on delegates:

delegate T Calc<T>(T a, T b) where T : struct;

Generally we know the pattern now. And without much explanation a quick summary should cover all generic types:

// generic delegate
delegate T myDelegate<T>(T t) where T : struct;

// generic method
void myMethod<T, U>(T a, T b, U c) {}

// generic class
class myClass<T> where T : System.IComparable<T>, IEnumerable<T> {}

// generic interface
interface IMyInterFace<out TResult, in TInput> {
    TResult DoSometing(TInput Args);
}

Interfaces can make use of the in and out keywords.
The out keyword declares a generic type parameter covariant. The in keyword makes it contravariant.
Covariance and contravariance were introduced when I described delegates https://csharphardcoreprogramming.wordpress.com/2013/12/16/delegates-basics/ .
The out keyword can only be used as an input parameter if it is a contravariant generic delegate.

interface ICovariant<out T> {
    void DoSomething(Action<T> xCallback);
}

The contravariant type (in) can only be used in method arguments and not as return types, it can also be used for generic constraints.

interface IContravariant<in T> {
    void DoSomething<U>() where U : T;
}

There are certain rules about inheritance.
A covariant class cannot inherit from a contravariant class.
A contravariant class cannot inherit from a covariant class.

interface ICovariant<out T> { }
interface IContravariant<in T> { }

// all ok
interface IInvariant1<T> : ICovariant<T> { }
interface IInvariant2<T> : IContravariant<T> { }
interface IInvariant3<T> : ICovariant<T>, IContravariant<T> { }
interface ICovariant1<out T> : ICovariant<T> { }
interface IContravariant1<in T> : IContravariant<T> { }

// compiler error. 
//interface ICovariant2<out T> : IContravariant<T> { }
//interface ICovariant3<out T> : ICovariant<T>, IContravariant<T> { }
//interface IContravariant2<in T> : ICovariant<T> { }
//interface IContravariant3<in T> : ICovariant<T>, IContravariant<T> { }

There is no generic type for Arrays. Backward compatibility did not allow an evolution here. Arrays are very basic, they can be used for high-performing applications. If Microsoft would make them more complex, we would somehow lose that benefit. My advice is to use generic collections/Lists instead. You can use T[], but this is rather a strongly typed array than a generic array.

public static void Generics9<T>() {
    T[] lArray = new T[10];
    foreach (T lElement in lArray) {
        Console.WriteLine(lElement.ToString());
    }
} //
Advertisements

Events (part 3, advanced)

Events: Let’s go multithreading! We want the crème de la crème. Well, multitasking is also fine.

The code does not need to run in a specific sequence. The required independence is given. Again, there are many ways to use multithreading. An easy approach is to start a task in each method that is called by the event.

C# does support BeginInvoke() for delegates. This method is not supported by the .NET Compact Framework though. We don’t care, because our hardcore programs are for serious applications, definitely not for mobile phone apps. Let’s see how good BeginInvoke() works. Maybe we don’t have to reinvent the wheel.

BeginInvoke() initiates asynchronous calls, it returns immediately and provides the IAsyncResult, which can be used to monitor the progress of the asynchronous call.
EndInvoke() retrieves the results. It blocks until the thread has completed.

You have the following options after calling BeginInvoke():
1) Call EndInvoke() to block the current thread until the call completes.
2) Obtain the WaitHandle from IAsyncResult.AsyncWaitHandle, use its WaitOne() and then call EndInvoke().
3) Poll the IAsyncResult to check the current state, after it has completed call EndInvoke().
4) Pass a callback to BeginInvoke(). The callback will use the ThreadPool to notify you. In the callback you have to call EndInvoke().

public event EventHandler OnChange;

public void DoSomeWork(object sender, object e) {
    Thread.Sleep(2100);
    Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + " mission accomplished!");
} //

public void RunMyExample() {
    OnChange += new EventHandler(DoSomeWork);
    //OnChange += new EventHandler(DoSomeWork);
    //OnChange += new EventHandler(DoSomeWork);

    IAsyncResult lAsyncResult;

    Console.WriteLine("Choice 1");
    lAsyncResult = OnChange.BeginInvoke(this, EventArgs.Empty, null, null);
    OnChange.EndInvoke(lAsyncResult);

    Console.WriteLine("Choice 2");
    lAsyncResult = OnChange.BeginInvoke(this, EventArgs.Empty, null, null);
    lAsyncResult.AsyncWaitHandle.WaitOne();

    Console.WriteLine("Choice 3");
    lAsyncResult = OnChange.BeginInvoke(this, EventArgs.Empty, null, null);
    while (!lAsyncResult.IsCompleted) {
        Thread.Sleep(500);
        Console.WriteLine("work still not completed :(");
    }

    Console.WriteLine("Choice 4"); 
    OnChange.BeginInvoke(this, EventArgs.Empty, (xAsyncResult) => {
            Console.WriteLine("callback running");
            OnChange.EndInvoke(xAsyncResult);
        }, null);

    Console.WriteLine("press return to exit the program");
    Console.ReadLine();
}//    

example output:
Choice 1
Thread 6 mission accomplished!
Choice 2
Thread 6 mission accomplished!
work still not completed 😦
work still not completed 😦
work still not completed 😦
work still not completed 😦
Thread 10 mission accomplished!
work still not completed 😦
press return to exit the program
Thread 6 mission accomplished!
callback running

After having lived such a nice life, we have to face a major issue with BeginInvoke(). Uncomment “//OnChange += new EventHandler(DoSomeWork);”, don’t get annoyed now!
You will get an error message saying

“The delegate must have only one target”.

Although the delegate class can deal with multiple targets, asynchronous calls accept just one target.

So let’s try something else.

    public event EventHandler OnChange;

    public void DoSomeWork(object sender, object e) {
        Thread.Sleep(2100);
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + " mission accomplished!");
    } //

    public void RunMyExample() {
        OnChange += new EventHandler(DoSomeWork);
        OnChange += new EventHandler((sender, e) => { throw new Exception("something went wrong"); });
        OnChange += new EventHandler(DoSomeWork);

        EventHandler lOnChange = OnChange;
        if (lOnChange == null) return;   // just to demonstrate the proper way to call events, not needed in this example                
        foreach (EventHandler d in lOnChange.GetInvocationList()) {
            Task lTask = Task.Factory.StartNew(() => d(this, EventArgs.Empty));
            lTask.ContinueWith((i) => { Console.WriteLine("Task canceled"); }, TaskContinuationOptions.OnlyOnCanceled);
            lTask.ContinueWith((i) => { Console.WriteLine("Task faulted"); }, TaskContinuationOptions.OnlyOnFaulted);
            lTask.ContinueWith((i) => { Console.WriteLine("Task completion"); }, TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        Console.WriteLine("press return to exit the program");
        Console.ReadLine();
    }//    

It seems that Microsoft has a serious bug here.This code does not execute properly each time. I guess it has to do with the asynchronous behaviour of StartNew(). It sometimes calls the wrong method DoSomeWork() three times and does not raise the exception.
It seems foreach overrides variable “d” before it is inserted in StartNew(). With a little tweak we can avoid this bug. We simply assign “d” to a new local variable. That way we have unique copies of “d”. Weird stuff, but that is the life of a coder sometimes.

public event EventHandler OnChange;

public void DoSomeWork(object sender, object e) {
    Thread.Sleep(2100);
    Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId + " mission accomplished!");
} //

public void RunMyExample() {
    OnChange += new EventHandler(DoSomeWork);
    OnChange += new EventHandler((sender, e) => { throw new Exception("something went wrong"); });
    OnChange += new EventHandler(DoSomeWork);

    EventHandler lOnChange = OnChange;
    if (lOnChange == null) return;   // just to demonstrate the proper way to call events, not needed in this example                
    foreach (EventHandler d in lOnChange.GetInvocationList()) {
        EventHandler e = d;
        Task lTask = Task.Factory.StartNew(() => e(this, EventArgs.Empty));
        lTask.ContinueWith((i) => { Console.WriteLine("Task canceled"); }, TaskContinuationOptions.OnlyOnCanceled);
        lTask.ContinueWith((i) => { Console.WriteLine("Task faulted"); }, TaskContinuationOptions.OnlyOnFaulted);
        lTask.ContinueWith((i) => { Console.WriteLine("Task completion"); }, TaskContinuationOptions.OnlyOnRanToCompletion);
    }

    Console.WriteLine("press return to exit the program");
    Console.ReadLine();
}//    

Example output:
press return to exit the program
Thread 11 mission accomplished!
Thread 10 mission accomplished!
Task completion
Task faulted
Task completion

This tiny tweak worked. You just have to know the compiler bugs. I hope this little notice saves you at least 3 hours of work.
You probably remember that we faced a similar issue in my post “Exiting Tasks (advanced)” https://csharphardcoreprogramming.wordpress.com/2013/12/11/exiting-tasks/ . I would suggest to only use Task.Factory.StartNew() with caution. Maybe it only happens in conjunction with lambda expressions.
The following code is also running very well. The variable “d” is not used directly in Task.Factory.StartNew().

...
 foreach (EventHandler d in lOnChange.GetInvocationList()) {
            Action a = () => d(this, EventArgs.Empty);
            Task lTask = Task.Factory.StartNew(a);
            lTask.ContinueWith((i) => { Console.WriteLine("Task canceled"); }, TaskContinuationOptions.OnlyOnCanceled);
            lTask.ContinueWith((i) => { Console.WriteLine("Task faulted"); }, TaskContinuationOptions.OnlyOnFaulted);
            lTask.ContinueWith((i) => { Console.WriteLine("Task completion"); }, TaskContinuationOptions.OnlyOnRanToCompletion);
        }
...

Events (part 2, advanced)

We are going to construct our custom event accessor now. It deals with additions and removals of subscriptions. Accessors do pretty much look like property definitions. But instead of set and get you have to use add and remove.

public class MyActionEvent4 {
    private object _Lock = new object();            // a new object simply to avoid lock conflicts
    private event EventHandler<MyArgs> _OnChange;
    private event EventHandler<MyArgs> OnChange {
        add {
            lock (_Lock) { _OnChange += value; }
        }
        remove {
            lock (_Lock) { _OnChange -= value; }
        }
    } //

    public void RaiseEvent() {
        lock (_Lock) {
            EventHandler<MyArgs> lHandler = _OnChange;
            if (lHandler == null) return;
            lHandler(this, new MyArgs(0));   
        }        
    }//
} // class

Now we have one big problem here. The RaiseEvent() method has to obtain a lock each time, which causes a serious impact on time sensitive programs. Luckily you do not need to care about changing subscriptions during the invocation. Delegate references are thread-safe, because they are immutable like strings. Let’s simply take the lock out of the RaiseEvent() method, et voilà!

public class MyActionEvent5 {
    private object _Lock = new object();
    private event EventHandler<MyArgs> _OnChange;
    private event EventHandler<MyArgs> OnChange {
        add {
            lock (_Lock) { _OnChange += value; }
        }
        remove {
            lock (_Lock) { _OnChange -= value; }
        }
    } //

    public void RaiseEvent() {
        EventHandler<MyArgs> lHandler = _OnChange;
        if (lHandler == null) return;
        lHandler(this, new MyArgs(0));   
    }//
} // class

It is clear that events are not delegates. They restrict access rights from outside of the event class. To describe events you could most likely say that they are wrappers around delegates.

Whenever an exception is thrown during an event call then all following calls will not be executed. And it is tricky to determine which calls were not executed, because the order of event calls is not guaranteed to be in sequence. In fact it does execute in sequence, but there is no guarantee.

static void EventExceptions1() {
    MyActionEvent3 lEvent = new MyActionEvent3();
    lEvent.OnChange += (sender, e) => Console.WriteLine("Executed subscription 1");
    lEvent.OnChange += (sender, e) => { throw new Exception("OMG!"); };
    lEvent.OnChange += (sender, e) => Console.WriteLine("Executed subscription 3");
    lEvent.RaiseEvent();
} //

So you have to deal with exceptions manually if you want to satisfy/execute as many event subscriptions as possible. You could add a try/catch block for each subscription. Or you could invoke the InvocationList yourself by calling the GetInvocationList() method [System.Delegate] and execute each item manually in a try/catch block. Let’s have a look at the following practical solution:

public class MyActionEvent6 {
    public event EventHandler OnChange = delegate { };

    public void RaiseEvent() {
        List<Exception> lExceptions = new List<Exception>();

        foreach (Delegate lHandler in OnChange.GetInvocationList()) {
            try { lHandler.DynamicInvoke(this, EventArgs.Empty); }
            catch (Exception ex) { lExceptions.Add(ex); }
        }

        if (lExceptions.Count > 0) throw new AggregateException(lExceptions);
    }//
} // class

static void EventExceptions6() {
    MyActionEvent6 lEvent = new MyActionEvent6();
    lEvent.OnChange += (sender, e) => Console.WriteLine("Executed subscription 1");
    lEvent.OnChange += (sender, e) => { throw new Exception("OMG!"); };
    lEvent.OnChange += (sender, e) => Console.WriteLine("Executed subscription 3");

    try { lEvent.RaiseEvent(); }
    catch (AggregateException ex) {
        foreach (Exception lException in ex.InnerExceptions) {
            Console.WriteLine(lException.InnerException.Message);
        }
    }
} //

Events (part 1, advanced)

Events link code dynamically together via subscriptions. There are many ways to achieve this. To better understand events, we will start with the old school approach. It is pretty much Java style. You would not do such in C#.

public interface IListener {
    void OnEvent(int xDummy);
} // interface

public class AnyClass {
    private List<Ilistener> _Listeners = new List<Ilistener>();

    public void AddListener(IListener xListener) {
        lock (_Listeners) { _Listeners.Add(xListener); }
    } //

    public void RemoveListener(IListener xListener) {
        lock (_Listeners) { _Listeners.Remove(xListener); }
    } //

    protected void RaiseEvent() {
        lock (_Listeners) {
            foreach (IListener lListener in _Listeners) lListener.OnEvent(0);
        }
    }//

    public void DoSomeCalc() {
        Console.WriteLine("calculating something");
        Console.WriteLine("done");
        Console.WriteLine("going to tell others");
        RaiseEvent();
    } //
} // class

public class MyLittleProgram : IListener {
    public void StartDemo() {
        AnyClass c = new AnyClass();
        c.AddListener(this);
        c.DoSomeCalc();
        c.RemoveListener(this);
    } //

    public void OnEvent(int xDummy) {
        Console.WriteLine("Hey, cool! I got a notification");
    } //
} // class

static void Main(string[] args) {    
    MyLittleProgram p = new MyLittleProgram();
    p.StartDemo();

    Console.ReadLine();
} //

Above example program uses a List that stores classes. An event is raised by iterating through that list and calling the desired method. This is a lot of code for something really simple.
In the post “Delegates (basics)” https://csharphardcoreprogramming.wordpress.com/2013/12/16/delegates-basics/ we have learned to use delegates. And let’s emphasize it again: We are talking about MulticastDelegates. In the post “Lambda expressions (advanced)” https://csharphardcoreprogramming.wordpress.com/2013/12/17/lambda-expressions-advanced/ we then came across Func and Action. The next step would be to make use of Action.

public class MyActionEvent {
    public Action OnChange { get; set; }

    public void RaiseEvent() {
        Action lAction = OnChange;
        if (lAction == null) return;
        lAction();
    }//
} // class

static void Main(string[] args) {
    MyActionEvent lEventClass = new MyActionEvent();
    lEventClass.OnChange += () => Console.WriteLine("I got a notification.");
    lEventClass.OnChange += () => Console.WriteLine("Me too.");
    lEventClass.RaiseEvent();

    Console.ReadLine();
} //

Notice that we used a local delegate variable (Action lAction = OnChange;) and did not call OnEvent directly. This is important in a multithreaded environment. Allthough it is unlikely, the event could still turn null before it gets raised.

Above code is much more legible now. But it is really bad practice. The event is accessible from outside. The class MyActionEvent loses control over the event. The Action OnChange is accessible and can be raised from outside the class. This is why C# implemented the “event” keyword. Code no longer uses public properties but public event fields, which are properly protected.
An event can only be assigned by using “+=”, whereas an Action can also be entirely overridden with “=”. It makes programming a little bit safer, you don’t run the risk of removing all previous subscriptions by mistake. Also events can only be raised by code within the same class. There is no way events could be raised from outside.

To make your life easier you can assign an empty delegate during the initialization process. By using “= delegate { };” there is no further need to check for the null condition, especially that no outside code can assign null to the event. Only code inside the class can assign null. Therefore the class is in full control of the event.

public class MyActionEvent2 {
    public event Action OnChange = delegate { };

    public void RaiseEvent() {
        OnChange();
        Console.WriteLine("number of event handlers: " + OnChange.GetInvocationList().Length);
    }//
} // class

Personally I do not like the approach with empty delegates. The number of delegates is artificially increased by one. A null check is pretty much using no time at all, so why should someone prefer to call an empty method each time an event is raised?

The next step is to replace the dirty Action by a proper delegate definition, which is EventHandler<>. By default its parameters are the sender object and some event arguments. This is a C# convention and should be followed. Surely you are familiar with such event calls from the Winforms/WPF environment.

public class MyArgs : EventArgs {
    public MyArgs(int xValue) {
        Value = xValue;
    } // constructor

    public int Value { get; set; }
} // class

public class MyActionEvent3 {
    public event EventHandler<myargs> OnChange;

    public void RaiseEvent() {
        EventHandler<myargs> lHandler = OnChange;
        if (lHandler == null) return;
        lHandler(this, new MyArgs(0));                
    }//
} // class

static void Main(string[] args) {
    MyActionEvent3 lEventClass = new MyActionEvent3();
    lEventClass.OnChange += (sender, e) => Console.WriteLine("Event raised, field value is: " + e.Value);            
    lEventClass.RaiseEvent();
    
    Console.ReadLine();
} //

Lambda expressions (advanced)

Well, I have used lambda expressions in previous posts already. I was expecting that you know them already.
A Lambda function does not have a name, therefore it is also refered to as anonymous function.
Let’s have a closer look now. In my last post I was introducing delegates and we started with the following example:

// methods
private double Multiply(double a, double b) { return a * b; }
private double Add(double a, double b) { return a + b; }

// a delegate for any of the above methods
private delegate double dCalc(double a, double b);

void Delegates1() {
    dCalc calc = Add; // creates a new delegate
    Console.WriteLine("Sum " + calc(6.0, 3.0));

    calc = Multiply; // creates a new delegate
    Console.WriteLine("Product " + calc(6.0, 3.0));

    Console.ReadLine();
} //

Above code can be shortened by using lambda expressions. It also becomes more legible then:

private delegate double dCalc(double a, double b);

void Lambda1() {
    dCalc calc = (x, y) => x + y;
    Console.WriteLine("Sum " + calc(6.0, 3.0));

    calc = (x, y) => x * y;
    Console.WriteLine("Product " + calc(6.0, 3.0));

    Console.ReadLine();
} //

(x, y) => x + y; is a lambda expression with x and y defined as doubles. The types were defined in the delegate dCalc, which has two doubles as input parameters and one double as return value. The “@” sign is pronounced “at”, likewise the “=>” sign is pronounced “go to” or “goes to”.
As usual you can use curly braces to group multiple statements:
(x, y) => { Console.WriteLine(“hello”); return x + y;}

You don’t have to use parentheses if you only have one parameter.
(x) => x + x;
equals
x => x + x;

And you don’t need the “return” when there is only one statement.
x => x + x;
equals
x => { return x + x; }

C# offers built-in types. They are Func and Action. You can use them to define delegates. Both can take between 0 and 16 parameters. Action has no return value, Func must define a return type in the last parameter.

void Lambda2() {
    // syntax  Func<first parameter type, second parameter type, return value type>
    Func<double, double, int> func = (x, y) => (int)(x + y);

    // syntax Action<first parameter type, second parameter type>
    Action<double, double> action = (x, y) => Console.WriteLine(x + y);
} //

Btw. you need empty parentheses whenever you don’t use any parameters.

Func<int> f = () => 2;

You can be more formal and declare types explicitly.

void Lambda3() {
    Func<double, double, int> func = (double x, double y) => (int)(x + y);
    Action<double, double> action = (double x, double y) => Console.WriteLine(x + y);
} //

If a delegate refers to a local variable it can happen that the local variable does not exist anymore at the time of the lambda expression/(code) execution. It is important to understand that C# is taking care of this problem. The lifetimes of local variables are extended to at least the lifetime of the longest-living delegate. This is called closure.

void Lambda4() {
    string s = "hello world";

    Action action = () => { Thread.Sleep(2000); Console.WriteLine(s); };
    Task.Factory.StartNew(action);

    // Exit the method before the task has completed.
    // This does not invalidate the string s !!!
} //

Delegates (basics)

A delegate is like an enhanced classical pointer. It is type-safe and needs a specific method signature. Delegates can invoke methods, thus they can be used for events.
To declare a delegate simply add the word “delegate” in front of a method definition.

// methods
private double Multiply(double a, double b) { return a * b; }
private double Add(double a, double b) { return a + b; }

// a delegate for any of the above methods
private delegate double dCalc(double a, double b);

Assign a method to a delegate and then use the delegate to call the method.

void Delegates1() {
    dCalc calc = Add; // creates a new delegate
    Console.WriteLine("Sum " + calc(6.0, 3.0));

    calc = Multiply; // creates a new delegate
    Console.WriteLine("Product " + calc(6.0, 3.0));

    Console.ReadLine();
} //

example output:
Sum 9
Product 18

You can use operators to add or remove delegates. The next example shows that a delegate can point to multiple methods. This can be done, because delegates inherit from the System.MulticastDelegate class, which in turn inherits from System.Delegate.

private delegate void dPrint();

private void PrintA() { Console.WriteLine("Print A"); }
private void PrintB() { Console.WriteLine("Print B"); }

void Delegates2() {
    Console.WriteLine("--------------------------------");
    dPrint print = PrintA;
    print += PrintB;
    Console.WriteLine("added A and B");
    print();

    Console.WriteLine("--------------------------------");
    print -= PrintA;
    Console.WriteLine("removed A");
    print();

    Console.ReadLine();
} //

example output:
——————————–
added A and B
Print A
Print B
——————————–
removed A
Print B

Delegates do have iterators. You can loop through and/or count them. By now you should easily understand that delegates have nothing to do with pointers (as eg. used in C++). They do not just point somewhere. A delegate is a complex class. And we are dealing with multicast delegates on top of that.

private delegate void dPrint();

private void PrintA() { Console.WriteLine("Print A"); }
private void PrintB() { Console.WriteLine("Print B"); }

void Delegates3() {
    dPrint print = PrintA;
    print += PrintB;
    print += PrintB;
    print();
    Console.WriteLine("number of invokes: " + print.GetInvocationList().GetLength(0));
    foreach (Delegate d in print.GetInvocationList()) {
        Console.WriteLine(d.Method.Name + "()");
    }

    Console.ReadLine();
} //

example output:
Print A
Print B
Print B
number of invokes: 3
PrintA()
PrintB()
PrintB()

There are some words to learn here:

Covariance describes a return value that is more derived than defined in the delegate.
Contravariance describes a method with parameters that are less derived than those defined in the delegate.
Invariant describes a generic type parameter that is neither marked covariant nor contravariant.
Variance Covariance and Contravariance are collectively called variance.

Covariance looks like standard polymorphism, whereas Contravariance seems counterintuitive. What is important to remember is that a covariant type parameter can be used as the return type of a delegate, and contravariant type parameters can be used as parameter types.

Contravariance was introduced in C# 4. Source code that did not compile in C# 3.5 is now compiling and running very well under C# 4. Contravariance is meaningful for write-only methods. So the input does not produce an output of the same hierarchy.

Covariance example:

class A { public int dummyA = 0; }
class B : A { public double dummyB = 0.0; }

delegate A dCovariance();

B Test() { return new B(); }

void Delegates4() {
    dCovariance covariance = Test;  // test returns class B, not class A as defined in the delegate

    foreach (Delegate d in covariance.GetInvocationList()) {
        Console.WriteLine(d.Method.Name + "()");
    }

    Console.ReadLine();
} //

example output:
Test()

Contravariance example:

class A { public int dummyA = 0; }
class B : A { public double dummyB = 0.0; }

void Test2(A xParameter) { return; }

delegate void dContravariance(B xClassB);

void Delegates5() {
    // The parameter in Test2() is of type class "A", but the
    // delegate was defined with a class "B" parameter.
    dContravariance contravariance = Test2;

    foreach (Delegate d in contravariance.GetInvocationList()) {
        Console.WriteLine(d.Method.Name + "()");
    }

    contravariance(new B());  // <= important !!!!

    Console.ReadLine();
} //

example output:
Test2()

When calling contravariance(…) we have to pass any class B instance as parameter. And the method Test2() has obviously no problems with this. Class B is more derived. It does make sense now that Test2() can be less derived, doesn’t it?

Contravariance will be discussed in more detail when looking at generic interfaces with the “in T” annotation. One commonly used contravariant interface is IComparer. Lean back for the moment and just have a quick look at a custom interface using the “in T” annotation. That should be enough for today.

interface IPerson<in T> {
    string Name { get; set; }
    int Age { get; set; }
}