Confessions of a .NET Developer!

Tricky delegates

One day I stumbled upon a curious thing that I noticed while working with delegates.
Let me explain with an example:

using System;
using System.Collections.Generic;

namespace Weird
{
    class Program
    {
        //Delegate declared
        private delegate void ShowValue();

        static void Main(string[] args)
        {
            List<ShowValue> lst = new List<ShowValue>();

            for (int j = 0; j < 5; j++)
            {
                //Instantiating the delegates
                lst.Add(delegate { Console.WriteLine(j); });
            }

            //Invoking the delegates
            //for (int i = 0; i < 5; i++)
            //{
            //    lst[i]();
            //}           
            //In short, using ForEach extension
            lst.ForEach((ShowValue sv) => { sv(); });

            Console.ReadLine();
        }
    }
}

So I have declared a delegate, instantiating and adding them into a List and then invoking them later.
What do you think is the answer? Most of you might be thinking its 0 1 2 3 4. Not quite correct!

This is the result:

Result

Result


Suprising isn’t it!
Now how did that happen, I started investigating. I started to read John Skeet’s C# in Depth, from here I got the idea. The thing is, the delegate actually captures the variable i. Behind the scene, when we declare a delegate, a separate class is created by the compiler which derives from the MultiCastDelegate class. The delegate instance in the for-loop will create a reference to the variable i. So each time it’s instantiated, it actually refers to the same variable. After the loop gets over, i will be 5 and hence when invoked, 5 will be printed.

For the solution, well its quite simple. Here it goes, first the code:

class Program
    {
        private delegate void ShowValue();

        static void Main(string[] args)
        {
            List<ShowValue> lst = new List<ShowValue>();

            for (int j = 0; j < 5; j++)
            {
                int k = j;
                lst.Add(delegate { Console.WriteLine(k); });
            }

            //for (int i = 0; i < 5; i++)
            //{
            //    lst[i]();
            //}           
            //In short, using ForEach extension
            lst.ForEach((ShowValue sv) => { sv(); });

            Console.ReadLine();
        }
    }

The only change I made is to add a new variable k in the for loop. The trick is, as a new k variable is created for every loop, the delegate will always capture a new k and hence references a different variable. And the result will be: 0 1 2 3 4

FinalResult

FinalResult

Perfect! Hope you got the idea.
Happy Coding! 🙂

Advertisements

June 30, 2011 Posted by | C Sharp | 1 Comment

How to dynamically load assemblies including unreferenced assemblies

This post will explain how to load the dll dynamically and use the class’s methods in that dll. We will use the Activator class to create an instance of a class from the dll and invoke the required methods. So lets get started.

First of all, create a base class library and name it as AClassLibrary:

ClassLibrary

ClassLibrary

Add a new class named AClass, it will look like this:

    public class AClass
    {
        public void WriteDefault()
        {
            Console.WriteLine("A text");
        }

        public void WriteIt(string text)
        {
            Console.WriteLine(text);
        }

        public void WriteIt(string text1, string text2)
        {
            Console.WriteLine(text1 + text2);
        }
    }

Do note that we have two overloaded functions named WriteIt, I will let you know its significance later.

Now lets create another Console Application project in the same solution named CaptureAssembly.
After that, Add Reference to the project AClassLibrary:

AddReference

AddReference

Before explaining, let me show you the whole code:

using System;
using System.Reflection;

namespace CaptureAssembly
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly a = Assembly.LoadFrom("AClassLibrary.dll");

            Type clsType = a.GetType("AClassLibrary.AClass");
            
            //Create the instance of the class
            object clsInstance = Activator.CreateInstance(clsType, null);

            //Calls the WriteDefault method of AClass
            clsType.InvokeMember("WriteDefault", BindingFlags.InvokeMethod, null, clsInstance, null);

            //Calls the WriteIt methods
            clsType.InvokeMember("WriteIt", BindingFlags.InvokeMethod, null, clsInstance, new object[] { "Hello", " Tarun Kumar" });
            clsType.InvokeMember("WriteIt", BindingFlags.InvokeMethod, null, clsInstance, new object[] { "Hello" });

            Console.ReadLine();
        }
    }
}

First we get the type of AClass using the Reflection. The Activator class will use it to create the instance of the class which we name it as clsInstance.
Next step is to call the 3 methods of AClass. We will use the InvokeMember property using clsType. Let’s take the case of the fist InvokeMethod. The first parameter will take the name of the method, second will help us streamline the search for the method as Reflection is used for this purpose. Third parameter is of no use for now. Fourth parameter, the target is the class instance named clsIntance and the last parameter will take the array of objects used to pass the parameters for the method, as WriteDefault doesn’t have any parameters, hence it will remain null.
The next two invoke methods is for the two overloaded methods WriteIt, the first one will call the method which has two parameters as we are passing two items in the object array(last parameter). As the second invoke method has one item in the object array, hence WriteIt(string text) will be called.

And here is the result:

Result

Result

For loading Unreferenced Assemblies

You can also load the assembly without adding any reference. Suppose the base class library(dll) is in some location, then we can use Assembly.LoadFile method to load the assembly.

Just replace

Assembly a = Assembly.LoadFrom("AClassLibrary.dll");

with

Assembly a = Assembly.LoadFile(@"C:\AClassLibrary\bin\Debug\AClassLibrary.dll");

and you will get the same result.

Happy coding!

June 30, 2011 Posted by | C Sharp, Winforms, WPF | 1 Comment